2 SQLite format specification:
3 - Initially only replaces sectors/ and sectors2/
5 If map.sqlite does not exist in the save dir
6 or the block was not found in the database
7 the map will try to load from sectors folder.
8 In either case, map.sqlite will be created
9 and all future saves will save there.
11 Structure of map.sqlite:
19 #include "mapsector.h"
26 #include "nodemetadata.h"
32 #include "util/directiontables.h"
33 #include "rollback_interface.h"
35 #include "database-sqlite3.h"
37 Database_SQLite3::Database_SQLite3(ServerMap *map, std::string savedir)
40 m_database_read = NULL;
41 m_database_write = NULL;
42 m_database_list = NULL;
47 int Database_SQLite3::Initialized(void)
49 return m_database ? 1 : 0;
52 void Database_SQLite3::beginSave() {
54 if(sqlite3_exec(m_database, "BEGIN;", NULL, NULL, NULL) != SQLITE_OK)
55 infostream<<"WARNING: beginSave() failed, saving might be slow.";
58 void Database_SQLite3::endSave() {
60 if(sqlite3_exec(m_database, "COMMIT;", NULL, NULL, NULL) != SQLITE_OK)
61 infostream<<"WARNING: endSave() failed, map might not have saved.";
64 void Database_SQLite3::createDirs(std::string path)
66 if(fs::CreateAllDirs(path) == false)
68 infostream<<DTIME<<"Database_SQLite3: Failed to create directory "
69 <<"\""<<path<<"\""<<std::endl;
70 throw BaseException("Database_SQLite3 failed to create directory");
74 void Database_SQLite3::verifyDatabase() {
79 std::string dbp = m_savedir + DIR_DELIM + "map.sqlite";
80 bool needs_create = false;
84 Open the database connection
87 createDirs(m_savedir); // ?
89 if(!fs::PathExists(dbp))
92 d = sqlite3_open_v2(dbp.c_str(), &m_database, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL);
94 infostream<<"WARNING: SQLite3 database failed to open: "<<sqlite3_errmsg(m_database)<<std::endl;
95 throw FileNotGoodException("Cannot open database file");
101 d = sqlite3_prepare(m_database, "SELECT `data` FROM `blocks` WHERE `pos`=? LIMIT 1", -1, &m_database_read, NULL);
103 infostream<<"WARNING: SQLite3 database read statment failed to prepare: "<<sqlite3_errmsg(m_database)<<std::endl;
104 throw FileNotGoodException("Cannot prepare read statement");
107 d = sqlite3_prepare(m_database, "REPLACE INTO `blocks` VALUES(?, ?)", -1, &m_database_write, NULL);
109 infostream<<"WARNING: SQLite3 database write statment failed to prepare: "<<sqlite3_errmsg(m_database)<<std::endl;
110 throw FileNotGoodException("Cannot prepare write statement");
113 d = sqlite3_prepare(m_database, "SELECT `pos` FROM `blocks`", -1, &m_database_list, NULL);
115 infostream<<"WARNING: SQLite3 database list statment failed to prepare: "<<sqlite3_errmsg(m_database)<<std::endl;
116 throw FileNotGoodException("Cannot prepare read statement");
119 infostream<<"ServerMap: SQLite3 database opened"<<std::endl;
123 void Database_SQLite3::saveBlock(MapBlock *block)
125 DSTACK(__FUNCTION_NAME);
127 Dummy blocks are not written
131 /*v3s16 p = block->getPos();
132 infostream<<"Database_SQLite3::saveBlock(): WARNING: Not writing dummy block "
133 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
137 // Format used for writing
138 u8 version = SER_FMT_VER_HIGHEST_WRITE;
140 v3s16 p3d = block->getPos();
144 v2s16 p2d(p3d.X, p3d.Z);
145 std::string sectordir = getSectorDir(p2d);
147 createDirs(sectordir);
149 std::string fullpath = sectordir+DIR_DELIM+getBlockFilename(p3d);
150 std::ofstream o(fullpath.c_str(), std::ios_base::binary);
151 if(o.good() == false)
152 throw FileNotGoodException("Cannot open block data");
155 [0] u8 serialization version
161 std::ostringstream o(std::ios_base::binary);
163 o.write((char*)&version, 1);
166 block->serialize(o, version, true);
168 // Write block to database
170 std::string tmp = o.str();
171 const char *bytes = tmp.c_str();
173 if(sqlite3_bind_int64(m_database_write, 1, getBlockAsInteger(p3d)) != SQLITE_OK)
174 infostream<<"WARNING: Block position failed to bind: "<<sqlite3_errmsg(m_database)<<std::endl;
175 if(sqlite3_bind_blob(m_database_write, 2, (void *)bytes, o.tellp(), NULL) != SQLITE_OK) // TODO this mught not be the right length
176 infostream<<"WARNING: Block data failed to bind: "<<sqlite3_errmsg(m_database)<<std::endl;
177 int written = sqlite3_step(m_database_write);
178 if(written != SQLITE_DONE)
179 infostream<<"WARNING: Block failed to save ("<<p3d.X<<", "<<p3d.Y<<", "<<p3d.Z<<") "
180 <<sqlite3_errmsg(m_database)<<std::endl;
181 // Make ready for later reuse
182 sqlite3_reset(m_database_write);
184 // We just wrote it to the disk so clear modified flag
185 block->resetModified();
188 MapBlock* Database_SQLite3::loadBlock(v3s16 blockpos)
190 v2s16 p2d(blockpos.X, blockpos.Z);
193 if(sqlite3_bind_int64(m_database_read, 1, getBlockAsInteger(blockpos)) != SQLITE_OK)
194 infostream<<"WARNING: Could not bind block position for load: "
195 <<sqlite3_errmsg(m_database)<<std::endl;
196 if(sqlite3_step(m_database_read) == SQLITE_ROW) {
198 Make sure sector is loaded
200 MapSector *sector = srvmap->createSector(p2d);
205 const char * data = (const char *)sqlite3_column_blob(m_database_read, 0);
206 size_t len = sqlite3_column_bytes(m_database_read, 0);
208 std::string datastr(data, len);
210 // srvmap->loadBlock(&datastr, blockpos, sector, false);
213 std::istringstream is(datastr, std::ios_base::binary);
215 u8 version = SER_FMT_VER_INVALID;
216 is.read((char*)&version, 1);
219 throw SerializationError("ServerMap::loadBlock(): Failed"
220 " to read MapBlock version");
222 MapBlock *block = NULL;
223 bool created_new = false;
224 block = sector->getBlockNoCreateNoEx(blockpos.Y);
227 block = sector->createBlankBlockNoInsert(blockpos.Y);
232 block->deSerialize(is, version, true);
234 // If it's a new block, insert it to the map
236 sector->insertBlock(block);
239 Save blocks loaded in old format in new format
242 //if(version < SER_FMT_VER_HIGHEST || save_after_load)
243 // Only save if asked to; no need to update version
244 //if(save_after_load)
247 // We just loaded it from, so it's up-to-date.
248 block->resetModified();
251 catch(SerializationError &e)
253 errorstream<<"Invalid block data in database"
254 <<" ("<<blockpos.X<<","<<blockpos.Y<<","<<blockpos.Z<<")"
255 <<" (SerializationError): "<<e.what()<<std::endl;
257 // TODO: Block should be marked as invalid in memory so that it is
258 // not touched but the game can run
260 if(g_settings->getBool("ignore_world_load_errors")){
261 errorstream<<"Ignoring block load error. Duck and cover! "
262 <<"(ignore_world_load_errors)"<<std::endl;
264 throw SerializationError("Invalid block data in database");
270 sqlite3_step(m_database_read);
271 // We should never get more than 1 row, so ok to reset
272 sqlite3_reset(m_database_read);
274 return srvmap->getBlockNoCreateNoEx(blockpos); // should not be using this here
276 sqlite3_reset(m_database_read);
280 void Database_SQLite3::createDatabase()
284 e = sqlite3_exec(m_database,
285 "CREATE TABLE IF NOT EXISTS `blocks` ("
286 "`pos` INT NOT NULL PRIMARY KEY,"
290 if(e == SQLITE_ABORT)
291 throw FileNotGoodException("Could not create sqlite3 database structure");
293 infostream<<"ServerMap: SQLite3 database structure was created";
297 void Database_SQLite3::listAllLoadableBlocks(core::list<v3s16> &dst)
301 while(sqlite3_step(m_database_list) == SQLITE_ROW)
303 sqlite3_int64 block_i = sqlite3_column_int64(m_database_list, 0);
304 v3s16 p = getIntegerAsBlock(block_i);
305 //dstream<<"block_i="<<block_i<<" p="<<PP(p)<<std::endl;
310 Database_SQLite3::~Database_SQLite3()
313 sqlite3_finalize(m_database_read);
315 sqlite3_finalize(m_database_write);
317 sqlite3_close(m_database);