cb0101a811f7ce46bb2f23d672b4b5e3c8bed86a
[oweals/minetest.git] / src / database-leveldb.cpp
1 #include "config.h"
2
3 #if USE_LEVELDB
4 /*
5 LevelDB databases
6 */
7
8
9 #include "map.h"
10 #include "mapsector.h"
11 #include "mapblock.h"
12 #include "main.h"
13 #include "filesys.h"
14 #include "voxel.h"
15 #include "porting.h"
16 #include "mapgen.h"
17 #include "nodemetadata.h"
18 #include "settings.h"
19 #include "log.h"
20 #include "profiler.h"
21 #include "nodedef.h"
22 #include "gamedef.h"
23 #include "util/directiontables.h"
24 #include "rollback_interface.h"
25
26 #include "database-leveldb.h"
27 #include "leveldb/db.h"
28
29 Database_LevelDB::Database_LevelDB(ServerMap *map, std::string savedir)
30 {
31         leveldb::Options options;
32         options.create_if_missing = true;
33         leveldb::Status status = leveldb::DB::Open(options, savedir + DIR_DELIM + "map.db", &m_database);
34         assert(status.ok());
35         srvmap = map;
36 }
37
38 int Database_LevelDB::Initialized(void)
39 {
40         return 1;
41 }
42
43 void Database_LevelDB::beginSave() {}
44 void Database_LevelDB::endSave() {}
45
46 void Database_LevelDB::saveBlock(MapBlock *block)
47 {
48         DSTACK(__FUNCTION_NAME);
49         /*
50                 Dummy blocks are not written
51         */
52         if(block->isDummy())
53         {
54                 return;
55         }
56
57         // Format used for writing
58         u8 version = SER_FMT_VER_HIGHEST_WRITE;
59         // Get destination
60         v3s16 p3d = block->getPos();
61
62         /*
63                 [0] u8 serialization version
64                 [1] data
65         */
66
67         std::ostringstream o(std::ios_base::binary);
68         o.write((char*)&version, 1);
69         // Write basic data
70         block->serialize(o, version, true);
71         // Write block to database
72         std::string tmp = o.str();
73
74         m_database->Put(leveldb::WriteOptions(), i64tos(getBlockAsInteger(p3d)), tmp);
75
76         // We just wrote it to the disk so clear modified flag
77         block->resetModified();
78 }
79
80 MapBlock* Database_LevelDB::loadBlock(v3s16 blockpos)
81 {
82         v2s16 p2d(blockpos.X, blockpos.Z);
83
84         std::string datastr;
85         leveldb::Status s = m_database->Get(leveldb::ReadOptions(), i64tos(getBlockAsInteger(blockpos)), &datastr);
86
87         if(s.ok()) {
88                 /*
89                         Make sure sector is loaded
90                 */
91                 MapSector *sector = srvmap->createSector(p2d);
92
93                 try {
94                         std::istringstream is(datastr, std::ios_base::binary);
95                         u8 version = SER_FMT_VER_INVALID;
96                         is.read((char*)&version, 1);
97
98                         if(is.fail())
99                                 throw SerializationError("ServerMap::loadBlock(): Failed"
100                                                      " to read MapBlock version");
101
102                         MapBlock *block = NULL;
103                         bool created_new = false;
104                         block = sector->getBlockNoCreateNoEx(blockpos.Y);
105                         if(block == NULL)
106                         {
107                                 block = sector->createBlankBlockNoInsert(blockpos.Y);
108                                 created_new = true;
109                         }
110                         // Read basic data
111                         block->deSerialize(is, version, true);
112                         // If it's a new block, insert it to the map
113                         if(created_new)
114                                 sector->insertBlock(block);
115                         /*
116                                 Save blocks loaded in old format in new format
117                         */
118
119                         //if(version < SER_FMT_VER_HIGHEST || save_after_load)
120                         // Only save if asked to; no need to update version
121                         //if(save_after_load)
122                         //      saveBlock(block);
123                         // We just loaded it from, so it's up-to-date.
124                         block->resetModified();
125
126                 }
127                 catch(SerializationError &e)
128                 {
129                         errorstream<<"Invalid block data in database"
130                                      <<" ("<<blockpos.X<<","<<blockpos.Y<<","<<blockpos.Z<<")"
131                                      <<" (SerializationError): "<<e.what()<<std::endl;
132                      // TODO: Block should be marked as invalid in memory so that it is
133                      // not touched but the game can run
134
135                         if(g_settings->getBool("ignore_world_load_errors")){
136                              errorstream<<"Ignoring block load error. Duck and cover! "
137                                              <<"(ignore_world_load_errors)"<<std::endl;
138                         } else {
139                              throw SerializationError("Invalid block data in database");
140                              //assert(0);
141                         }
142                 }
143
144                 return srvmap->getBlockNoCreateNoEx(blockpos);  // should not be using this here
145         }
146         return(NULL);
147 }
148
149 void Database_LevelDB::listAllLoadableBlocks(std::list<v3s16> &dst)
150 {
151         leveldb::Iterator* it = m_database->NewIterator(leveldb::ReadOptions());
152         for (it->SeekToFirst(); it->Valid(); it->Next()) {
153                 dst.push_back(getIntegerAsBlock(stoi64(it->key().ToString())));
154         }
155         assert(it->status().ok());  // Check for any errors found during the scan
156         delete it;
157 }
158
159 Database_LevelDB::~Database_LevelDB()
160 {
161         delete m_database;
162 }
163 #endif