3 Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 SQLite format specification:
22 - Initially only replaces sectors/ and sectors2/
24 If map.sqlite does not exist in the save dir
25 or the block was not found in the database
26 the map will try to load from sectors folder.
27 In either case, map.sqlite will be created
28 and all future saves will save there.
30 Structure of map.sqlite:
38 #include "database-sqlite3.h"
41 #include "mapsector.h"
43 #include "serialization.h"
48 Database_SQLite3::Database_SQLite3(ServerMap *map, std::string savedir)
51 m_database_read = NULL;
52 m_database_write = NULL;
53 m_database_list = NULL;
58 int Database_SQLite3::Initialized(void)
60 return m_database ? 1 : 0;
63 void Database_SQLite3::beginSave() {
65 if(sqlite3_exec(m_database, "BEGIN;", NULL, NULL, NULL) != SQLITE_OK)
66 infostream<<"WARNING: beginSave() failed, saving might be slow.";
69 void Database_SQLite3::endSave() {
71 if(sqlite3_exec(m_database, "COMMIT;", NULL, NULL, NULL) != SQLITE_OK)
72 infostream<<"WARNING: endSave() failed, map might not have saved.";
75 void Database_SQLite3::createDirs(std::string path)
77 if(fs::CreateAllDirs(path) == false)
79 infostream<<DTIME<<"Database_SQLite3: Failed to create directory "
80 <<"\""<<path<<"\""<<std::endl;
81 throw BaseException("Database_SQLite3 failed to create directory");
85 void Database_SQLite3::verifyDatabase() {
89 std::string dbp = m_savedir + DIR_DELIM "map.sqlite";
90 bool needs_create = false;
93 // Open the database connection
95 createDirs(m_savedir); // ?
97 if(!fs::PathExists(dbp))
100 d = sqlite3_open_v2(dbp.c_str(), &m_database, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL);
102 infostream<<"WARNING: SQLite3 database failed to open: "<<sqlite3_errmsg(m_database)<<std::endl;
103 throw FileNotGoodException("Cannot open database file");
109 std::string querystr = std::string("PRAGMA synchronous = ")
110 + itos(g_settings->getU16("sqlite_synchronous"));
111 d = sqlite3_exec(m_database, querystr.c_str(), NULL, NULL, NULL);
113 infostream<<"WARNING: Database pragma set failed: "
114 <<sqlite3_errmsg(m_database)<<std::endl;
115 throw FileNotGoodException("Cannot set pragma");
118 d = sqlite3_prepare(m_database, "SELECT `data` FROM `blocks` WHERE `pos`=? LIMIT 1", -1, &m_database_read, NULL);
120 infostream<<"WARNING: SQLite3 database read statment failed to prepare: "<<sqlite3_errmsg(m_database)<<std::endl;
121 throw FileNotGoodException("Cannot prepare read statement");
124 d = sqlite3_prepare(m_database, "REPLACE INTO `blocks` VALUES(?, ?)", -1, &m_database_write, NULL);
126 infostream<<"WARNING: SQLite3 database write statment failed to prepare: "<<sqlite3_errmsg(m_database)<<std::endl;
127 throw FileNotGoodException("Cannot prepare write statement");
130 d = sqlite3_prepare(m_database, "SELECT `pos` FROM `blocks`", -1, &m_database_list, NULL);
132 infostream<<"WARNING: SQLite3 database list statment failed to prepare: "<<sqlite3_errmsg(m_database)<<std::endl;
133 throw FileNotGoodException("Cannot prepare read statement");
136 infostream<<"ServerMap: SQLite3 database opened"<<std::endl;
139 bool Database_SQLite3::saveBlock(MapBlock *block)
141 DSTACK(__FUNCTION_NAME);
143 v3s16 p3d = block->getPos();
146 Dummy blocks are not written, but is not a save failure
150 errorstream << "WARNING: saveBlock: Not writing dummy block "
151 << PP(p3d) << std::endl;
155 // Format used for writing
156 u8 version = SER_FMT_VER_HIGHEST_WRITE;
159 v2s16 p2d(p3d.X, p3d.Z);
160 std::string sectordir = getSectorDir(p2d);
162 createDirs(sectordir);
164 std::string fullpath = sectordir+DIR_DELIM+getBlockFilename(p3d);
165 std::ofstream o(fullpath.c_str(), std::ios_base::binary);
166 if(o.good() == false)
167 throw FileNotGoodException("Cannot open block data");
170 [0] u8 serialization version
176 std::ostringstream o(std::ios_base::binary);
178 o.write((char *)&version, 1);
181 block->serialize(o, version, true);
183 // Write block to database
184 std::string tmp = o.str();
186 if (sqlite3_bind_int64(m_database_write, 1, getBlockAsInteger(p3d)) != SQLITE_OK) {
187 errorstream << "WARNING: saveBlock: Block position failed to bind: "
188 << PP(p3d) << ": " << sqlite3_errmsg(m_database) << std::endl;
189 sqlite3_reset(m_database_write);
193 if (sqlite3_bind_blob(m_database_write, 2, (void *)tmp.c_str(), tmp.size(), NULL) != SQLITE_OK) {
194 errorstream << "WARNING: saveBlock: Block data failed to bind: "
195 << PP(p3d) << ": " << sqlite3_errmsg(m_database) << std::endl;
196 sqlite3_reset(m_database_write);
200 if (sqlite3_step(m_database_write) != SQLITE_DONE) {
201 errorstream << "WARNING: saveBlock: Block failed to save "
202 << PP(p3d) << ": " << sqlite3_errmsg(m_database) << std::endl;
203 sqlite3_reset(m_database_write);
207 // We just wrote it to the disk so clear modified flag
208 block->resetModified();
209 sqlite3_reset(m_database_write);
213 MapBlock* Database_SQLite3::loadBlock(v3s16 blockpos)
215 v2s16 p2d(blockpos.X, blockpos.Z);
218 if (sqlite3_bind_int64(m_database_read, 1, getBlockAsInteger(blockpos)) != SQLITE_OK) {
219 infostream << "WARNING: Could not bind block position for load: "
220 << sqlite3_errmsg(m_database)<<std::endl;
223 if (sqlite3_step(m_database_read) == SQLITE_ROW) {
225 Make sure sector is loaded
227 MapSector *sector = srvmap->createSector(p2d);
232 const char *data = (const char *)sqlite3_column_blob(m_database_read, 0);
233 size_t len = sqlite3_column_bytes(m_database_read, 0);
234 if (data == NULL || len == 0) {
235 errorstream << "Blank block data in database (data == NULL || len"
236 " == 0) (" << blockpos.X << "," << blockpos.Y << ","
237 << blockpos.Z << ")" << std::endl;
239 if (g_settings->getBool("ignore_world_load_errors")) {
240 errorstream << "Ignoring block load error. Duck and cover! "
241 << "(ignore_world_load_errors)" << std::endl;
243 throw SerializationError("Blank block data in database");
248 std::string datastr(data, len);
250 //srvmap->loadBlock(&datastr, blockpos, sector, false);
253 std::istringstream is(datastr, std::ios_base::binary);
255 u8 version = SER_FMT_VER_INVALID;
256 is.read((char *)&version, 1);
259 throw SerializationError("ServerMap::loadBlock(): Failed"
260 " to read MapBlock version");
262 MapBlock *block = NULL;
263 bool created_new = false;
264 block = sector->getBlockNoCreateNoEx(blockpos.Y);
267 block = sector->createBlankBlockNoInsert(blockpos.Y);
272 block->deSerialize(is, version, true);
274 // If it's a new block, insert it to the map
276 sector->insertBlock(block);
279 Save blocks loaded in old format in new format
281 //if(version < SER_FMT_VER_HIGHEST || save_after_load)
282 // Only save if asked to; no need to update version
283 //if(save_after_load)
286 // We just loaded it from, so it's up-to-date.
287 block->resetModified();
289 catch (SerializationError &e)
291 errorstream << "Invalid block data in database"
292 << " (" << blockpos.X << "," << blockpos.Y << "," << blockpos.Z << ")"
293 << " (SerializationError): " << e.what() << std::endl;
295 // TODO: Block should be marked as invalid in memory so that it is
296 // not touched but the game can run
298 if (g_settings->getBool("ignore_world_load_errors")) {
299 errorstream << "Ignoring block load error. Duck and cover! "
300 << "(ignore_world_load_errors)" << std::endl;
302 throw SerializationError("Invalid block data in database");
307 sqlite3_step(m_database_read);
308 // We should never get more than 1 row, so ok to reset
309 sqlite3_reset(m_database_read);
311 return srvmap->getBlockNoCreateNoEx(blockpos); // should not be using this here
313 sqlite3_reset(m_database_read);
317 void Database_SQLite3::createDatabase()
321 e = sqlite3_exec(m_database,
322 "CREATE TABLE IF NOT EXISTS `blocks` ("
323 "`pos` INT NOT NULL PRIMARY KEY,"
327 if(e == SQLITE_ABORT)
328 throw FileNotGoodException("Could not create sqlite3 database structure");
330 infostream<<"ServerMap: SQLite3 database structure was created";
334 void Database_SQLite3::listAllLoadableBlocks(std::list<v3s16> &dst)
338 while(sqlite3_step(m_database_list) == SQLITE_ROW)
340 sqlite3_int64 block_i = sqlite3_column_int64(m_database_list, 0);
341 v3s16 p = getIntegerAsBlock(block_i);
342 //dstream<<"block_i="<<block_i<<" p="<<PP(p)<<std::endl;
348 #define FINALIZE_STATEMENT(statement) \
350 rc = sqlite3_finalize(statement); \
351 if ( rc != SQLITE_OK ) \
352 errorstream << "Database_SQLite3::~Database_SQLite3():" \
353 << "Failed to finalize: " << #statement << ": rc=" << rc << std::endl;
355 Database_SQLite3::~Database_SQLite3()
359 FINALIZE_STATEMENT(m_database_read)
360 FINALIZE_STATEMENT(m_database_write)
361 FINALIZE_STATEMENT(m_database_list)
364 rc = sqlite3_close(m_database);
366 if (rc != SQLITE_OK) {
367 errorstream << "Database_SQLite3::~Database_SQLite3(): "
368 << "Failed to close database: rc=" << rc << std::endl;