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() {
90 std::string dbp = m_savedir + DIR_DELIM + "map.sqlite";
91 bool needs_create = false;
95 Open the database connection
98 createDirs(m_savedir); // ?
100 if(!fs::PathExists(dbp))
103 d = sqlite3_open_v2(dbp.c_str(), &m_database, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL);
105 infostream<<"WARNING: SQLite3 database failed to open: "<<sqlite3_errmsg(m_database)<<std::endl;
106 throw FileNotGoodException("Cannot open database file");
112 std::string querystr = std::string("PRAGMA synchronous = ")
113 + itos(g_settings->getU16("sqlite_synchronous"));
114 d = sqlite3_exec(m_database, querystr.c_str(), NULL, NULL, NULL);
116 infostream<<"WARNING: Database pragma set failed: "
117 <<sqlite3_errmsg(m_database)<<std::endl;
118 throw FileNotGoodException("Cannot set pragma");
121 d = sqlite3_prepare(m_database, "SELECT `data` FROM `blocks` WHERE `pos`=? LIMIT 1", -1, &m_database_read, NULL);
123 infostream<<"WARNING: SQLite3 database read statment failed to prepare: "<<sqlite3_errmsg(m_database)<<std::endl;
124 throw FileNotGoodException("Cannot prepare read statement");
127 d = sqlite3_prepare(m_database, "REPLACE INTO `blocks` VALUES(?, ?)", -1, &m_database_write, NULL);
129 infostream<<"WARNING: SQLite3 database write statment failed to prepare: "<<sqlite3_errmsg(m_database)<<std::endl;
130 throw FileNotGoodException("Cannot prepare write statement");
133 d = sqlite3_prepare(m_database, "SELECT `pos` FROM `blocks`", -1, &m_database_list, NULL);
135 infostream<<"WARNING: SQLite3 database list statment failed to prepare: "<<sqlite3_errmsg(m_database)<<std::endl;
136 throw FileNotGoodException("Cannot prepare read statement");
139 infostream<<"ServerMap: SQLite3 database opened"<<std::endl;
143 void Database_SQLite3::saveBlock(MapBlock *block)
145 DSTACK(__FUNCTION_NAME);
147 Dummy blocks are not written
151 /*v3s16 p = block->getPos();
152 infostream<<"Database_SQLite3::saveBlock(): WARNING: Not writing dummy block "
153 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
157 // Format used for writing
158 u8 version = SER_FMT_VER_HIGHEST_WRITE;
160 v3s16 p3d = block->getPos();
164 v2s16 p2d(p3d.X, p3d.Z);
165 std::string sectordir = getSectorDir(p2d);
167 createDirs(sectordir);
169 std::string fullpath = sectordir+DIR_DELIM+getBlockFilename(p3d);
170 std::ofstream o(fullpath.c_str(), std::ios_base::binary);
171 if(o.good() == false)
172 throw FileNotGoodException("Cannot open block data");
175 [0] u8 serialization version
181 std::ostringstream o(std::ios_base::binary);
183 o.write((char*)&version, 1);
186 block->serialize(o, version, true);
188 // Write block to database
190 std::string tmp = o.str();
191 const char *bytes = tmp.c_str();
193 if(sqlite3_bind_int64(m_database_write, 1, getBlockAsInteger(p3d)) != SQLITE_OK)
194 infostream<<"WARNING: Block position failed to bind: "<<sqlite3_errmsg(m_database)<<std::endl;
195 if(sqlite3_bind_blob(m_database_write, 2, (void *)bytes, o.tellp(), NULL) != SQLITE_OK) // TODO this mught not be the right length
196 infostream<<"WARNING: Block data failed to bind: "<<sqlite3_errmsg(m_database)<<std::endl;
197 int written = sqlite3_step(m_database_write);
198 if(written != SQLITE_DONE)
199 infostream<<"WARNING: Block failed to save ("<<p3d.X<<", "<<p3d.Y<<", "<<p3d.Z<<") "
200 <<sqlite3_errmsg(m_database)<<std::endl;
201 // Make ready for later reuse
202 sqlite3_reset(m_database_write);
204 // We just wrote it to the disk so clear modified flag
205 block->resetModified();
208 MapBlock* Database_SQLite3::loadBlock(v3s16 blockpos)
210 v2s16 p2d(blockpos.X, blockpos.Z);
213 if (sqlite3_bind_int64(m_database_read, 1, getBlockAsInteger(blockpos)) != SQLITE_OK) {
214 infostream << "WARNING: Could not bind block position for load: "
215 << sqlite3_errmsg(m_database)<<std::endl;
218 if (sqlite3_step(m_database_read) == SQLITE_ROW) {
220 Make sure sector is loaded
222 MapSector *sector = srvmap->createSector(p2d);
227 const char *data = (const char *)sqlite3_column_blob(m_database_read, 0);
228 size_t len = sqlite3_column_bytes(m_database_read, 0);
229 if (data == NULL || len == 0) {
230 errorstream << "Blank block data in database (data == NULL || len"
231 " == 0) (" << blockpos.X << "," << blockpos.Y << ","
232 << blockpos.Z << ")" << std::endl;
234 if (g_settings->getBool("ignore_world_load_errors")) {
235 errorstream << "Ignoring block load error. Duck and cover! "
236 << "(ignore_world_load_errors)" << std::endl;
238 throw SerializationError("Blank block data in database");
243 std::string datastr(data, len);
245 //srvmap->loadBlock(&datastr, blockpos, sector, false);
248 std::istringstream is(datastr, std::ios_base::binary);
250 u8 version = SER_FMT_VER_INVALID;
251 is.read((char *)&version, 1);
254 throw SerializationError("ServerMap::loadBlock(): Failed"
255 " to read MapBlock version");
257 MapBlock *block = NULL;
258 bool created_new = false;
259 block = sector->getBlockNoCreateNoEx(blockpos.Y);
262 block = sector->createBlankBlockNoInsert(blockpos.Y);
267 block->deSerialize(is, version, true);
269 // If it's a new block, insert it to the map
271 sector->insertBlock(block);
274 Save blocks loaded in old format in new format
276 //if(version < SER_FMT_VER_HIGHEST || save_after_load)
277 // Only save if asked to; no need to update version
278 //if(save_after_load)
281 // We just loaded it from, so it's up-to-date.
282 block->resetModified();
284 catch (SerializationError &e)
286 errorstream << "Invalid block data in database"
287 << " (" << blockpos.X << "," << blockpos.Y << "," << blockpos.Z << ")"
288 << " (SerializationError): " << e.what() << std::endl;
290 // TODO: Block should be marked as invalid in memory so that it is
291 // not touched but the game can run
293 if (g_settings->getBool("ignore_world_load_errors")) {
294 errorstream << "Ignoring block load error. Duck and cover! "
295 << "(ignore_world_load_errors)" << std::endl;
297 throw SerializationError("Invalid block data in database");
302 sqlite3_step(m_database_read);
303 // We should never get more than 1 row, so ok to reset
304 sqlite3_reset(m_database_read);
306 return srvmap->getBlockNoCreateNoEx(blockpos); // should not be using this here
308 sqlite3_reset(m_database_read);
312 void Database_SQLite3::createDatabase()
316 e = sqlite3_exec(m_database,
317 "CREATE TABLE IF NOT EXISTS `blocks` ("
318 "`pos` INT NOT NULL PRIMARY KEY,"
322 if(e == SQLITE_ABORT)
323 throw FileNotGoodException("Could not create sqlite3 database structure");
325 infostream<<"ServerMap: SQLite3 database structure was created";
329 void Database_SQLite3::listAllLoadableBlocks(std::list<v3s16> &dst)
333 while(sqlite3_step(m_database_list) == SQLITE_ROW)
335 sqlite3_int64 block_i = sqlite3_column_int64(m_database_list, 0);
336 v3s16 p = getIntegerAsBlock(block_i);
337 //dstream<<"block_i="<<block_i<<" p="<<PP(p)<<std::endl;
343 #define FINALIZE_STATEMENT(statement) \
345 rc = sqlite3_finalize(statement); \
346 if ( rc != SQLITE_OK ) \
347 errorstream << "Database_SQLite3::~Database_SQLite3():" \
348 << "Failed to finalize: " << #statement << ": rc=" << rc << std::endl;
350 Database_SQLite3::~Database_SQLite3()
354 FINALIZE_STATEMENT(m_database_read)
355 FINALIZE_STATEMENT(m_database_write)
356 FINALIZE_STATEMENT(m_database_list)
359 rc = sqlite3_close(m_database);
361 if (rc != SQLITE_OK) {
362 errorstream << "Database_SQLite3::~Database_SQLite3(): "
363 << "Failed to close database: rc=" << rc << std::endl;