Fix sqlite3 map shutdown fails due to missing to finalize list statement
[oweals/minetest.git] / src / rollback.cpp
1 /*
2 Minetest
3 Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
4
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.
9
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.
14
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.
18 */
19
20 #include "rollback.h"
21 #include <fstream>
22 #include <list>
23 #include <sstream>
24 #include "log.h"
25 #include "mapnode.h"
26 #include "gamedef.h"
27 #include "nodedef.h"
28 #include "util/serialize.h"
29 #include "util/string.h"
30 #include "util/numeric.h"
31 #include "inventorymanager.h" // deserializing InventoryLocations
32 #include "sqlite3.h"
33 #include "filesys.h"
34
35 #define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")"
36
37 #define POINTS_PER_NODE (16.0)
38
39 std::string dbp;
40 sqlite3* dbh;
41 sqlite3_stmt* dbs_insert;
42 sqlite3_stmt* dbs_replace;
43 sqlite3_stmt* dbs_select;
44 sqlite3_stmt* dbs_select_range;
45 sqlite3_stmt* dbs_select_withActor;
46 sqlite3_stmt* dbs_knownActor_select;
47 sqlite3_stmt* dbs_knownActor_insert;
48 sqlite3_stmt* dbs_knownNode_select;
49 sqlite3_stmt* dbs_knownNode_insert;
50
51 struct Stack {
52         int node;
53         int quantity;
54 };
55 struct ActionRow {
56         int         id;
57         int         actor;
58         time_t      timestamp;
59         int         type;
60         std::string location, list;
61         int         index, add;
62         Stack       stack;
63         int         nodeMeta;
64         int         x, y, z;
65         int         oldNode;
66         int         oldParam1, oldParam2;
67         std::string oldMeta;
68         int         newNode;
69         int         newParam1, newParam2;
70         std::string newMeta;
71         int         guessed;
72 };
73
74 struct Entity {
75         int         id;
76         std::string name;
77 };
78
79 typedef std::vector<Entity> Entities;
80
81 Entities KnownActors;
82 Entities KnownNodes;
83
84 void registerNewActor(int id, std::string name)
85 {
86         Entity newActor;
87
88         newActor.id   = id;
89         newActor.name = name;
90
91         KnownActors.push_back(newActor);
92
93         //std::cout << "New actor registered: " << id << " | " << name << std::endl;
94 }
95
96 void registerNewNode(int id, std::string name)
97 {
98         Entity newNode;
99
100         newNode.id   = id;
101         newNode.name = name;
102
103         KnownNodes.push_back(newNode);
104
105         //std::cout << "New node registered: " << id << " | " << name << std::endl;
106 }
107
108 int getActorId(std::string name)
109 {
110         Entities::const_iterator iter;
111
112         for (iter = KnownActors.begin(); iter != KnownActors.end(); ++iter)
113                 if (iter->name == name) {
114                         return iter->id;
115                 }
116
117         sqlite3_reset(dbs_knownActor_insert);
118         sqlite3_bind_text(dbs_knownActor_insert, 1, name.c_str(), -1, NULL);
119         sqlite3_step(dbs_knownActor_insert);
120
121         int id = sqlite3_last_insert_rowid(dbh);
122
123         //std::cout << "Actor ID insert returns " << insert << std::endl;
124
125         registerNewActor(id, name);
126
127         return id;
128 }
129
130 int getNodeId(std::string name)
131 {
132         Entities::const_iterator iter;
133
134         for (iter = KnownNodes.begin(); iter != KnownNodes.end(); ++iter)
135                 if (iter->name == name) {
136                         return iter->id;
137                 }
138
139         sqlite3_reset(dbs_knownNode_insert);
140         sqlite3_bind_text(dbs_knownNode_insert, 1, name.c_str(), -1, NULL);
141         sqlite3_step(dbs_knownNode_insert);
142
143         int id = sqlite3_last_insert_rowid(dbh);
144
145         registerNewNode(id, name);
146
147         return id;
148 }
149
150 const char * getActorName(int id)
151 {
152         Entities::const_iterator iter;
153
154         //std::cout << "getActorName of id " << id << std::endl;
155
156         for (iter = KnownActors.begin(); iter != KnownActors.end(); ++iter)
157                 if (iter->id == id) {
158                         return iter->name.c_str();
159                 }
160
161         return "";
162 }
163
164 const char * getNodeName(int id)
165 {
166         Entities::const_iterator iter;
167
168         //std::cout << "getNodeName of id " << id << std::endl;
169
170         for (iter = KnownNodes.begin(); iter != KnownNodes.end(); ++iter)
171                 if (iter->id == id) {
172                         return iter->name.c_str();
173                 }
174
175         return "";
176 }
177
178 Stack getStackFromString(std::string text)
179 {
180         Stack stack;
181
182         size_t off = text.find_last_of(" ");
183
184         stack.node     = getNodeId(text.substr(0, off));
185         stack.quantity = atoi(text.substr(off + 1).c_str());
186
187         return stack;
188 }
189
190 std::string getStringFromStack(Stack stack)
191 {
192         std::string text;
193
194         text.append(getNodeName(stack.node));
195         text.append(" ");
196         text.append(itos(stack.quantity));
197
198         return text;
199 }
200
201 bool SQL_createDatabase(void)
202 {
203         infostream << "CreateDB:" << dbp << std::endl;
204
205         int dbs = sqlite3_exec(dbh,
206                 "CREATE TABLE IF NOT EXISTS `actor` ("
207                         "`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,"
208                         "`name` TEXT NOT NULL);"
209                         "CREATE TABLE IF NOT EXISTS `node` ("
210                         "`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,"
211                         "`name` TEXT NOT NULL);"
212                 "CREATE TABLE IF NOT EXISTS `action` ("
213                         "`id` INTEGER PRIMARY KEY AUTOINCREMENT,"
214                         "`actor` INTEGER NOT NULL,"
215                         "`timestamp` TIMESTAMP NOT NULL,"
216                         "`type` INTEGER NOT NULL,"
217                         "`list` TEXT,"
218                         "`index` INTEGER,"
219                         "`add` INTEGER,"
220                         "`stackNode` INTEGER,"
221                         "`stackQuantity` INTEGER,"
222                         "`nodeMeta` INTEGER,"
223                         "`x` INT,"
224                         "`y` INT,"
225                         "`z` INT,"
226                         "`oldNode` INTEGER,"
227                         "`oldParam1` INTEGER,"
228                         "`oldParam2` INTEGER,"
229                         "`oldMeta` TEXT,"
230                         "`newNode` INTEGER,"
231                         "`newParam1` INTEGER,"
232                         "`newParam2` INTEGER,"
233                         "`newMeta` TEXT,"
234                         "`guessedActor` INTEGER,"
235                         "FOREIGN KEY (`actor`)   REFERENCES `actor`(`id`),"
236                         "FOREIGN KEY (`oldNode`) REFERENCES `node`(`id`),"
237                         "FOREIGN KEY (`newNode`) REFERENCES `node`(`id`));"
238                 "CREATE INDEX IF NOT EXISTS `actionActor` ON `action`(`actor`);"
239                 "CREATE INDEX IF NOT EXISTS `actionTimestamp` ON `action`(`timestamp`);",
240                 NULL, NULL, NULL);
241         if (dbs == SQLITE_ABORT) {
242                 throw FileNotGoodException("Could not create sqlite3 database structure");
243         } else if (dbs != 0) {
244                 throw FileNotGoodException("SQL Rollback: Exec statement to create table structure returned a non-zero value");
245         } else {
246                 infostream << "SQL Rollback: SQLite3 database structure was created" << std::endl;
247         }
248
249         return true;
250 }
251 void SQL_databaseCheck(void)
252 {
253         if (dbh) {
254                 return;
255         }
256
257         infostream << "Database connection setup" << std::endl;
258
259         bool needsCreate = !fs::PathExists(dbp);
260         int  dbo = sqlite3_open_v2(dbp.c_str(), &dbh, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE,
261                                    NULL);
262
263         if (dbo != SQLITE_OK) {
264                 infostream << "SQLROLLBACK: SQLite3 database failed to open: "
265                            << sqlite3_errmsg(dbh) << std::endl;
266                 throw FileNotGoodException("Cannot open database file");
267         }
268
269         if (needsCreate) {
270                 SQL_createDatabase();
271         }
272
273         int dbr;
274
275         dbr = sqlite3_prepare_v2(dbh,
276                 "INSERT INTO `action` ("
277                 "       `actor`, `timestamp`, `type`,"
278                 "       `list`, `index`, `add`, `stackNode`, `stackQuantity`, `nodeMeta`,"
279                 "       `x`, `y`, `z`,"
280                 "       `oldNode`, `oldParam1`, `oldParam2`, `oldMeta`,"
281                 "       `newNode`, `newParam1`, `newParam2`, `newMeta`,"
282                 "       `guessedActor`"
283                 ") VALUES ("
284                 "       ?, ?, ?,"
285                 "       ?, ?, ?, ?, ?, ?,"
286                 "       ?, ?, ?,"
287                 "       ?, ?, ?, ?,"
288                 "       ?, ?, ?, ?,"
289                 "       ?"
290                 ");",
291                 -1, &dbs_insert, NULL);
292
293         if (dbr != SQLITE_OK) {
294                 throw FileNotGoodException(sqlite3_errmsg(dbh));
295         }
296
297         dbr = sqlite3_prepare_v2(dbh,
298                 "REPLACE INTO `action` ("
299                 "       `actor`, `timestamp`, `type`,"
300                 "       `list`, `index`, `add`, `stackNode`, `stackQuantity`, `nodeMeta`,"
301                 "       `x`, `y`, `z`,"
302                 "       `oldNode`, `oldParam1`, `oldParam2`, `oldMeta`,"
303                 "       `newNode`, `newParam1`, `newParam2`, `newMeta`,"
304                 "       `guessedActor`, `id`"
305                 ") VALUES ("
306                 "       ?, ?, ?,"
307                 "       ?, ?, ?, ?, ?, ?,"
308                 "       ?, ?, ?,"
309                 "       ?, ?, ?, ?,"
310                 "       ?, ?, ?, ?,"
311                 "       ?, ?"
312                 ");",
313                 -1, &dbs_replace, NULL);
314
315         if (dbr != SQLITE_OK) {
316                 throw FileNotGoodException(sqlite3_errmsg(dbh));
317         }
318
319         dbr = sqlite3_prepare_v2(dbh,
320                 "SELECT"
321                 "       `actor`, `timestamp`, `type`,"
322                 "       `list`, `index`, `add`, `stackNode`, `stackQuantity`, `nodemeta`,"
323                 "       `x`, `y`, `z`,"
324                 "       `oldNode`, `oldParam1`, `oldParam2`, `oldMeta`,"
325                 "       `newNode`, `newParam1`, `newParam2`, `newMeta`,"
326                 "       `guessedActor`"
327                 " FROM  `action`"
328                 " WHERE `timestamp` >= ?"
329                 " ORDER BY `timestamp` DESC, `id` DESC",
330                 -1, &dbs_select, NULL);
331         if (dbr != SQLITE_OK) {
332                 throw FileNotGoodException(itos(dbr).c_str());
333         }
334
335         dbr = sqlite3_prepare_v2(dbh,
336                 "SELECT"
337                 "       `actor`, `timestamp`, `type`,"
338                 "       `list`, `index`, `add`, `stackNode`, `stackQuantity`, `nodemeta`,"
339                 "       `x`, `y`, `z`,"
340                 "       `oldNode`, `oldParam1`, `oldParam2`, `oldMeta`,"
341                 "       `newNode`, `newParam1`, `newParam2`, `newMeta`,"
342                 "       `guessedActor`"
343                 " FROM  `action`"
344                 " WHERE `timestamp` >= ?"
345                 " AND   `x` IS NOT NULL"
346                 " AND   `y` IS NOT NULL"
347                 " AND   `z` IS NOT NULL"
348                 " AND   ABS(`x` - ?) <= ?"
349                 " AND   ABS(`y` - ?) <= ?"
350                 " AND   ABS(`z` - ?) <= ?"
351                 " ORDER BY `timestamp` DESC, `id` DESC"
352                 " LIMIT 0,?",
353                 -1, &dbs_select_range, NULL);
354         if (dbr != SQLITE_OK) {
355                 throw FileNotGoodException(itos(dbr).c_str());
356         }
357
358         dbr = sqlite3_prepare_v2(dbh,
359                 "SELECT"
360                 "       `actor`, `timestamp`, `type`,"
361                 "       `list`, `index`, `add`, `stackNode`, `stackQuantity`, `nodemeta`,"
362                 "       `x`, `y`, `z`,"
363                 "       `oldNode`, `oldParam1`, `oldParam2`, `oldMeta`,"
364                 "       `newNode`, `newParam1`, `newParam2`, `newMeta`,"
365                 "       `guessedActor`"
366                 " FROM  `action`"
367                 " WHERE `timestamp` >= ?"
368                 " AND   `actor` = ?"
369                 " ORDER BY `timestamp` DESC, `id` DESC",
370                 -1, &dbs_select_withActor, NULL);
371         if (dbr != SQLITE_OK) {
372                 throw FileNotGoodException(itos(dbr).c_str());
373         }
374
375         dbr = sqlite3_prepare_v2(dbh, "SELECT `id`, `name` FROM `actor`", -1,
376                                  &dbs_knownActor_select, NULL);
377         if (dbr != SQLITE_OK) {
378                 throw FileNotGoodException(itos(dbr).c_str());
379         }
380
381         dbr = sqlite3_prepare_v2(dbh, "INSERT INTO `actor` (`name`) VALUES (?)", -1,
382                                  &dbs_knownActor_insert, NULL);
383         if (dbr != SQLITE_OK) {
384                 throw FileNotGoodException(itos(dbr).c_str());
385         }
386
387         dbr = sqlite3_prepare_v2(dbh, "SELECT `id`, `name` FROM `node`", -1,
388                                  &dbs_knownNode_select, NULL);
389         if (dbr != SQLITE_OK) {
390                 throw FileNotGoodException(itos(dbr).c_str());
391         }
392
393         dbr = sqlite3_prepare_v2(dbh, "INSERT INTO `node` (`name`) VALUES (?)", -1,
394                                  &dbs_knownNode_insert, NULL);
395         if (dbr != SQLITE_OK) {
396                 throw FileNotGoodException(itos(dbr).c_str());
397         }
398
399         infostream << "SQL prepared statements setup correctly" << std::endl;
400
401         int select;
402
403         sqlite3_reset(dbs_knownActor_select);
404         while (SQLITE_ROW == (select = sqlite3_step(dbs_knownActor_select)))
405                 registerNewActor(
406                         sqlite3_column_int(dbs_knownActor_select, 0),
407                         reinterpret_cast<const char *>(sqlite3_column_text(dbs_knownActor_select, 1))
408                 );
409
410         sqlite3_reset(dbs_knownNode_select);
411         while (SQLITE_ROW == (select = sqlite3_step(dbs_knownNode_select)))
412                 registerNewNode(
413                         sqlite3_column_int(dbs_knownNode_select, 0),
414                         reinterpret_cast<const char *>(sqlite3_column_text(dbs_knownNode_select, 1))
415                 );
416
417         return;
418 }
419 bool SQL_registerRow(ActionRow row)
420 {
421         SQL_databaseCheck();
422
423         sqlite3_stmt * dbs_do = (row.id) ? dbs_replace : dbs_insert;
424
425         /*
426         std::cout
427                 << (row.id? "Replacing": "Inserting")
428                 << " ActionRow" << std::endl;
429         */
430         sqlite3_reset(dbs_do);
431
432         int bind [22], ii = 0;
433         bool nodeMeta = false;
434
435         bind[ii++] = sqlite3_bind_int(dbs_do, 1, row.actor);
436         bind[ii++] = sqlite3_bind_int64(dbs_do, 2, row.timestamp);
437         bind[ii++] = sqlite3_bind_int(dbs_do, 3, row.type);
438
439         if (row.type == RollbackAction::TYPE_MODIFY_INVENTORY_STACK) {
440                 std::string loc         = row.location;
441                 std::string locType     = loc.substr(0, loc.find(":"));
442                 nodeMeta = (locType == "nodemeta");
443
444                 bind[ii++] = sqlite3_bind_text(dbs_do, 4, row.list.c_str(), row.list.size(), NULL);
445                 bind[ii++] = sqlite3_bind_int(dbs_do, 5, row.index);
446                 bind[ii++] = sqlite3_bind_int(dbs_do, 6, row.add);
447                 bind[ii++] = sqlite3_bind_int(dbs_do, 7, row.stack.node);
448                 bind[ii++] = sqlite3_bind_int(dbs_do, 8, row.stack.quantity);
449                 bind[ii++] = sqlite3_bind_int(dbs_do, 9, (int) nodeMeta);
450
451                 if (nodeMeta) {
452                         std::string x, y, z;
453                         int     l, r;
454                         l = loc.find(':') + 1;
455                         r = loc.find(',');
456                         x = loc.substr(l, r - l);
457                         l = r + 1;
458                         r = loc.find(',', l);
459                         y = loc.substr(l, r - l);
460                         z = loc.substr(r + 1);
461                         bind[ii++] = sqlite3_bind_int(dbs_do, 10, atoi(x.c_str()));
462                         bind[ii++] = sqlite3_bind_int(dbs_do, 11, atoi(y.c_str()));
463                         bind[ii++] = sqlite3_bind_int(dbs_do, 12, atoi(z.c_str()));
464                 }
465         } else {
466                 bind[ii++] = sqlite3_bind_null(dbs_do, 4);
467                 bind[ii++] = sqlite3_bind_null(dbs_do, 5);
468                 bind[ii++] = sqlite3_bind_null(dbs_do, 6);
469                 bind[ii++] = sqlite3_bind_null(dbs_do, 7);
470                 bind[ii++] = sqlite3_bind_null(dbs_do, 8);
471                 bind[ii++] = sqlite3_bind_null(dbs_do, 9);
472         }
473
474         if (row.type == RollbackAction::TYPE_SET_NODE) {
475                 bind[ii++] = sqlite3_bind_int(dbs_do, 10, row.x);
476                 bind[ii++] = sqlite3_bind_int(dbs_do, 11, row.y);
477                 bind[ii++] = sqlite3_bind_int(dbs_do, 12, row.z);
478                 bind[ii++] = sqlite3_bind_int(dbs_do, 13, row.oldNode);
479                 bind[ii++] = sqlite3_bind_int(dbs_do, 14, row.oldParam1);
480                 bind[ii++] = sqlite3_bind_int(dbs_do, 15, row.oldParam2);
481                 bind[ii++] = sqlite3_bind_text(dbs_do, 16, row.oldMeta.c_str(), row.oldMeta.size(), NULL);
482                 bind[ii++] = sqlite3_bind_int(dbs_do, 17, row.newNode);
483                 bind[ii++] = sqlite3_bind_int(dbs_do, 18, row.newParam1);
484                 bind[ii++] = sqlite3_bind_int(dbs_do, 19, row.newParam2);
485                 bind[ii++] = sqlite3_bind_text(dbs_do, 20, row.newMeta.c_str(), row.newMeta.size(), NULL);
486                 bind[ii++] = sqlite3_bind_int(dbs_do, 21, row.guessed ? 1 : 0);
487         } else {
488                 if (!nodeMeta) {
489                         bind[ii++] = sqlite3_bind_null(dbs_do, 10);
490                         bind[ii++] = sqlite3_bind_null(dbs_do, 11);
491                         bind[ii++] = sqlite3_bind_null(dbs_do, 12);
492                 }
493                 bind[ii++] = sqlite3_bind_null(dbs_do, 13);
494                 bind[ii++] = sqlite3_bind_null(dbs_do, 14);
495                 bind[ii++] = sqlite3_bind_null(dbs_do, 15);
496                 bind[ii++] = sqlite3_bind_null(dbs_do, 16);
497                 bind[ii++] = sqlite3_bind_null(dbs_do, 17);
498                 bind[ii++] = sqlite3_bind_null(dbs_do, 18);
499                 bind[ii++] = sqlite3_bind_null(dbs_do, 19);
500                 bind[ii++] = sqlite3_bind_null(dbs_do, 20);
501                 bind[ii++] = sqlite3_bind_null(dbs_do, 21);
502         }
503
504         if (row.id) {
505                 bind[ii++] = sqlite3_bind_int(dbs_do, 22, row.id);
506         }
507
508         for (ii = 0; ii < 20; ++ii)
509                 if (bind[ii] != SQLITE_OK)
510                         infostream
511                                         << "WARNING: failed to bind param " << ii + 1
512                                         << " when inserting an entry in table setnode" << std::endl;
513
514         /*
515         std::cout << "========DB-WRITTEN==========" << std::endl;
516         std::cout << "id:        " << row.id << std::endl;
517         std::cout << "actor:     " << row.actor << std::endl;
518         std::cout << "time:      " << row.timestamp << std::endl;
519         std::cout << "type:      " << row.type << std::endl;
520         if (row.type == RollbackAction::TYPE_MODIFY_INVENTORY_STACK)
521         {
522                 std::cout << "Location:   " << row.location << std::endl;
523                 std::cout << "List:       " << row.list << std::endl;
524                 std::cout << "Index:      " << row.index << std::endl;
525                 std::cout << "Add:        " << row.add << std::endl;
526                 std::cout << "Stack:      " << row.stack << std::endl;
527         }
528         if (row.type == RollbackAction::TYPE_SET_NODE)
529         {
530                 std::cout << "x:         " << row.x << std::endl;
531                 std::cout << "y:         " << row.y << std::endl;
532                 std::cout << "z:         " << row.z << std::endl;
533                 std::cout << "oldNode:   " << row.oldNode << std::endl;
534                 std::cout << "oldParam1: " << row.oldParam1 << std::endl;
535                 std::cout << "oldParam2: " << row.oldParam2 << std::endl;
536                 std::cout << "oldMeta:   " << row.oldMeta << std::endl;
537                 std::cout << "newNode:   " << row.newNode << std::endl;
538                 std::cout << "newParam1: " << row.newParam1 << std::endl;
539                 std::cout << "newParam2: " << row.newParam2 << std::endl;
540                 std::cout << "newMeta:   " << row.newMeta << std::endl;
541                 std::cout << "DESERIALIZE" << row.newMeta.c_str() << std::endl;
542                 std::cout << "guessed:   " << row.guessed << std::endl;
543         }
544         */
545
546         int written = sqlite3_step(dbs_do);
547
548         return written == SQLITE_DONE;
549
550         //if  (written != SQLITE_DONE)
551         //       std::cout << "WARNING: rollback action not written: " << sqlite3_errmsg(dbh) << std::endl;
552         //else std::cout << "Action correctly inserted via SQL" << std::endl;
553 }
554 std::list<ActionRow> actionRowsFromSelect(sqlite3_stmt* stmt)
555 {
556         std::list<ActionRow> rows;
557         const unsigned char * text;
558         size_t size;
559
560         while (SQLITE_ROW == sqlite3_step(stmt)) {
561                 ActionRow row;
562
563                 row.actor     = sqlite3_column_int(stmt, 0);
564                 row.timestamp = sqlite3_column_int64(stmt, 1);
565                 row.type      = sqlite3_column_int(stmt, 2);
566
567                 if (row.type == RollbackAction::TYPE_MODIFY_INVENTORY_STACK) {
568                         text               = sqlite3_column_text(stmt, 3);
569                         size               = sqlite3_column_bytes(stmt, 3);
570                         row.list           = std::string(reinterpret_cast<const char*>(text), size);
571                         row.index          = sqlite3_column_int(stmt, 4);
572                         row.add            = sqlite3_column_int(stmt, 5);
573                         row.stack.node     = sqlite3_column_int(stmt, 6);
574                         row.stack.quantity = sqlite3_column_int(stmt, 7);
575                         row.nodeMeta       = sqlite3_column_int(stmt, 8);
576                 }
577
578                 if (row.type == RollbackAction::TYPE_SET_NODE || row.nodeMeta) {
579                         row.x = sqlite3_column_int(stmt,  9);
580                         row.y = sqlite3_column_int(stmt, 10);
581                         row.z = sqlite3_column_int(stmt, 11);
582                 }
583
584                 if (row.type == RollbackAction::TYPE_SET_NODE) {
585                         row.oldNode             = sqlite3_column_int(stmt, 12);
586                         row.oldParam1 = sqlite3_column_int(stmt, 13);
587                         row.oldParam2 = sqlite3_column_int(stmt, 14);
588                         text          = sqlite3_column_text(stmt, 15);
589                         size          = sqlite3_column_bytes(stmt, 15);
590                         row.oldMeta   = std::string(reinterpret_cast<const char*>(text), size);
591                         row.newNode   = sqlite3_column_int(stmt, 16);
592                         row.newParam1 = sqlite3_column_int(stmt, 17);
593                         row.newParam2 = sqlite3_column_int(stmt, 18);
594                         text          = sqlite3_column_text(stmt, 19);
595                         size          = sqlite3_column_bytes(stmt, 19);
596                         row.newMeta   = std::string(reinterpret_cast<const char*>(text), size);
597                         row.guessed   = sqlite3_column_int(stmt, 20);
598                 }
599
600                 row.location = row.nodeMeta ? "nodemeta:" : getActorName(row.actor);
601
602                 if (row.nodeMeta) {
603                         row.location.append(itos(row.x));
604                         row.location.append(",");
605                         row.location.append(itos(row.y));
606                         row.location.append(",");
607                         row.location.append(itos(row.z));
608                 }
609
610                 /*
611                 std::cout << "=======SELECTED==========" << "\n";
612                 std::cout << "Actor: " << row.actor << "\n";
613                 std::cout << "Timestamp: " << row.timestamp << "\n";
614
615                 if (row.type == RollbackAction::TYPE_MODIFY_INVENTORY_STACK)
616                 {
617                         std::cout << "list: " << row.list << "\n";
618                         std::cout << "index: " << row.index << "\n";
619                         std::cout << "add: " << row.add << "\n";
620                         std::cout << "stackNode: " << row.stack.node << "\n";
621                         std::cout << "stackQuantity: " << row.stack.quantity << "\n";
622                         if (row.nodeMeta)
623                         {
624                                 std::cout << "X: " << row.x << "\n";
625                                 std::cout << "Y: " << row.y << "\n";
626                                 std::cout << "Z: " << row.z << "\n";
627                         }
628                         std::cout << "Location: " << row.location << "\n";
629                 }
630                         else
631                 {
632                         std::cout << "X: " << row.x << "\n";
633                         std::cout << "Y: " << row.y << "\n";
634                         std::cout << "Z: " << row.z << "\n";
635                         std::cout << "oldNode: " << row.oldNode << "\n";
636                         std::cout << "oldParam1: " << row.oldParam1 << "\n";
637                         std::cout << "oldParam2: " << row.oldParam2 << "\n";
638                         std::cout << "oldMeta: " << row.oldMeta << "\n";
639                         std::cout << "newNode: " << row.newNode << "\n";
640                         std::cout << "newParam1: " << row.newParam1 << "\n";
641                         std::cout << "newParam2: " << row.newParam2 << "\n";
642                         std::cout << "newMeta: " << row.newMeta << "\n";
643                         std::cout << "guessed: " << row.guessed << "\n";
644                 }
645                 */
646
647                 rows.push_back(row);
648         }
649
650         return rows;
651 }
652 ActionRow actionRowFromRollbackAction(RollbackAction action)
653 {
654         ActionRow row;
655
656         row.id        = 0;
657         row.actor     = getActorId(action.actor);
658         row.timestamp = action.unix_time;
659         row.type      = action.type;
660
661         if (row.type == RollbackAction::TYPE_MODIFY_INVENTORY_STACK) {
662                 row.location = action.inventory_location;
663                 row.list     = action.inventory_list;
664                 row.index    = action.inventory_index;
665                 row.add      = action.inventory_add;
666                 row.stack    = getStackFromString(action.inventory_stack);
667         } else {
668                 row.x         = action.p.X;
669                 row.y         = action.p.Y;
670                 row.z         = action.p.Z;
671                 row.oldNode   = getNodeId(action.n_old.name);
672                 row.oldParam1 = action.n_old.param1;
673                 row.oldParam2 = action.n_old.param2;
674                 row.oldMeta   = action.n_old.meta;
675                 row.newNode   = getNodeId(action.n_new.name);
676                 row.newParam1 = action.n_new.param1;
677                 row.newParam2 = action.n_new.param2;
678                 row.newMeta   = action.n_new.meta;
679                 row.guessed   = action.actor_is_guess;
680         }
681
682         return row;
683 }
684 std::list<RollbackAction> rollbackActionsFromActionRows(std::list<ActionRow> rows)
685 {
686         std::list<RollbackAction> actions;
687         std::list<ActionRow>::const_iterator it;
688
689         for (it = rows.begin(); it != rows.end(); ++it) {
690                 RollbackAction action;
691                 action.actor     = (it->actor) ? getActorName(it->actor) : "";
692                 action.unix_time = it->timestamp;
693                 action.type      = static_cast<RollbackAction::Type>(it->type);
694
695                 switch (action.type) {
696                 case RollbackAction::TYPE_MODIFY_INVENTORY_STACK:
697
698                         action.inventory_location = it->location.c_str();
699                         action.inventory_list     = it->list;
700                         action.inventory_index    = it->index;
701                         action.inventory_add      = it->add;
702                         action.inventory_stack    = getStringFromStack(it->stack);
703                         break;
704
705                 case RollbackAction::TYPE_SET_NODE:
706
707                         action.p            = v3s16(it->x, it->y, it->z);
708                         action.n_old.name   = getNodeName(it->oldNode);
709                         action.n_old.param1 = it->oldParam1;
710                         action.n_old.param2 = it->oldParam2;
711                         action.n_old.meta   = it->oldMeta;
712                         action.n_new.name   = getNodeName(it->newNode);
713                         action.n_new.param1 = it->newParam1;
714                         action.n_new.param2 = it->newParam2;
715                         action.n_new.meta   = it->newMeta;
716                         break;
717
718                 default:
719
720                         throw ("W.T.F.");
721                         break;
722                 }
723
724                 actions.push_back(action);
725         }
726
727         return actions;
728 }
729
730 std::list<ActionRow> SQL_getRowsSince(time_t firstTime, std::string actor = "")
731 {
732         sqlite3_stmt *dbs_stmt = (!actor.length()) ? dbs_select : dbs_select_withActor;
733         sqlite3_reset(dbs_stmt);
734         sqlite3_bind_int64(dbs_stmt, 1, firstTime);
735
736         if (actor.length()) {
737                 sqlite3_bind_int(dbs_stmt, 2, getActorId(actor));
738         }
739
740         return actionRowsFromSelect(dbs_stmt);
741 }
742
743 std::list<ActionRow> SQL_getRowsSince_range(time_t firstTime, v3s16 p, int range,
744                 int limit)
745 {
746         sqlite3_stmt *stmt = dbs_select_range;
747         sqlite3_reset(stmt);
748
749         sqlite3_bind_int64(stmt, 1, firstTime);
750         sqlite3_bind_int(stmt, 2, (int) p.X);
751         sqlite3_bind_int(stmt, 3, range);
752         sqlite3_bind_int(stmt, 4, (int) p.Y);
753         sqlite3_bind_int(stmt, 5, range);
754         sqlite3_bind_int(stmt, 6, (int) p.Z);
755         sqlite3_bind_int(stmt, 7, range);
756         sqlite3_bind_int(stmt, 8, limit);
757
758         return actionRowsFromSelect(stmt);
759 }
760
761 std::list<RollbackAction> SQL_getActionsSince_range(time_t firstTime, v3s16 p, int range,
762                 int limit)
763 {
764         std::list<ActionRow> rows = SQL_getRowsSince_range(firstTime, p, range, limit);
765
766         return rollbackActionsFromActionRows(rows);
767 }
768
769 std::list<RollbackAction> SQL_getActionsSince(time_t firstTime, std::string actor = "")
770 {
771         std::list<ActionRow> rows = SQL_getRowsSince(firstTime, actor);
772         return rollbackActionsFromActionRows(rows);
773 }
774
775 void TXT_migrate(std::string filepath)
776 {
777         std::cout << "Migrating from rollback.txt to rollback.sqlite" << std::endl;
778         SQL_databaseCheck();
779
780         std::ifstream fh(filepath.c_str(), std::ios::in | std::ios::ate);
781         if (!fh.good()) {
782                 throw ("DIE");
783         }
784
785         std::streampos filesize = fh.tellg();
786
787         if (filesize > 10) {
788                 fh.seekg(0);
789
790                 std::string bit;
791                 int i   = 0;
792                 int id  = 1;
793                 time_t t   = 0;
794                 do {
795                         ActionRow row;
796
797                         row.id = id;
798
799                         // Get the timestamp
800                         std::getline(fh, bit, ' ');
801                         bit = trim(bit);
802                         if (!atoi(trim(bit).c_str())) {
803                                 std::getline(fh, bit);
804                                 continue;
805                         }
806                         row.timestamp = atoi(bit.c_str());
807
808                         // Get the actor
809                         row.actor = getActorId(trim(deSerializeJsonString(fh)));
810
811                         // Get the action type
812                         std::getline(fh, bit, '[');
813                         std::getline(fh, bit, ' ');
814
815                         if (bit == "modify_inventory_stack") {
816                                 row.type = RollbackAction::TYPE_MODIFY_INVENTORY_STACK;
817                         }
818
819                         if (bit == "set_node") {
820                                 row.type = RollbackAction::TYPE_SET_NODE;
821                         }
822
823                         if (row.type == RollbackAction::TYPE_MODIFY_INVENTORY_STACK) {
824                                 row.location = trim(deSerializeJsonString(fh));
825                                 std::getline(fh, bit, ' ');
826                                 row.list     = trim(deSerializeJsonString(fh));
827                                 std::getline(fh, bit, ' ');
828                                 std::getline(fh, bit, ' ');
829                                 row.index    = atoi(trim(bit).c_str());
830                                 std::getline(fh, bit, ' ');
831                                 row.add      = (int)(trim(bit) == "add");
832                                 row.stack    = getStackFromString(trim(deSerializeJsonString(fh)));
833                                 std::getline(fh, bit);
834                         } else if (row.type == RollbackAction::TYPE_SET_NODE) {
835                                 std::getline(fh, bit, '(');
836                                 std::getline(fh, bit, ',');
837                                 row.x       = atoi(trim(bit).c_str());
838                                 std::getline(fh, bit, ',');
839                                 row.y       = atoi(trim(bit).c_str());
840                                 std::getline(fh, bit, ')');
841                                 row.z       = atoi(trim(bit).c_str());
842                                 std::getline(fh, bit, ' ');
843                                 row.oldNode = getNodeId(trim(deSerializeJsonString(fh)));
844                                 std::getline(fh, bit, ' ');
845                                 std::getline(fh, bit, ' ');
846                                 row.oldParam1 = atoi(trim(bit).c_str());
847                                 std::getline(fh, bit, ' ');
848                                 row.oldParam2 = atoi(trim(bit).c_str());
849                                 row.oldMeta   = trim(deSerializeJsonString(fh));
850                                 std::getline(fh, bit, ' ');
851                                 row.newNode   = getNodeId(trim(deSerializeJsonString(fh)));
852                                 std::getline(fh, bit, ' ');
853                                 std::getline(fh, bit, ' ');
854                                 row.newParam1 = atoi(trim(bit).c_str());
855                                 std::getline(fh, bit, ' ');
856                                 row.newParam2 = atoi(trim(bit).c_str());
857                                 row.newMeta   = trim(deSerializeJsonString(fh));
858                                 std::getline(fh, bit, ' ');
859                                 std::getline(fh, bit, ' ');
860                                 std::getline(fh, bit);
861                                 row.guessed = (int)(trim(bit) == "actor_is_guess");
862                         }
863
864                         /*
865                         std::cout << "==========READ===========" << std::endl;
866                         std::cout << "time:      " << row.timestamp << std::endl;
867                         std::cout << "actor:     " << row.actor << std::endl;
868                         std::cout << "type:      " << row.type << std::endl;
869                         if (row.type == RollbackAction::TYPE_MODIFY_INVENTORY_STACK)
870                         {
871                                 std::cout << "Location:   " << row.location << std::endl;
872                                 std::cout << "List:       " << row.list << std::endl;
873                                 std::cout << "Index:      " << row.index << std::endl;
874                                 std::cout << "Add:        " << row.add << std::endl;
875                                 std::cout << "Stack:      " << row.stack << std::endl;
876                         }
877                         if (row.type == RollbackAction::TYPE_SET_NODE)
878                         {
879                                 std::cout << "x:         " << row.x << std::endl;
880                                 std::cout << "y:         " << row.y << std::endl;
881                                 std::cout << "z:         " << row.z << std::endl;
882                                 std::cout << "oldNode:   " << row.oldNode << std::endl;
883                                 std::cout << "oldParam1: " << row.oldParam1 << std::endl;
884                                 std::cout << "oldParam2: " << row.oldParam2 << std::endl;
885                                 std::cout << "oldMeta:   " << row.oldMeta << std::endl;
886                                 std::cout << "newNode:   " << row.newNode << std::endl;
887                                 std::cout << "newParam1: " << row.newParam1 << std::endl;
888                                 std::cout << "newParam2: " << row.newParam2 << std::endl;
889                                 std::cout << "newMeta:   " << row.newMeta << std::endl;
890                                 std::cout << "guessed:   " << row.guessed << std::endl;
891                         }
892                         */
893
894                         if (i == 0) {
895                                 t = time(0);
896                                 sqlite3_exec(dbh, "BEGIN", NULL, NULL, NULL);
897                         }
898
899                         SQL_registerRow(row);
900                         ++i;
901
902                         if (time(0) - t) {
903                                 sqlite3_exec(dbh, "COMMIT", NULL, NULL, NULL);
904                                 t = time(0) - t;
905                                 std::cout
906                                                 << " Done: " << (int)(((float) fh.tellg() / (float) filesize) * 100) << "%"
907                                                 << " Speed: " << i / t << "/second     \r" << std::flush;
908                                 i = 0;
909                         }
910
911                         ++id;
912                 } while (!fh.eof() && fh.good());
913         } else {
914                 errorstream << "Empty rollback log" << std::endl;
915         }
916
917         std::cout
918                         << " Done: 100%                                   " << std::endl
919                         << " Now you can delete the old rollback.txt file." << std::endl;
920 }
921
922 // Get nearness factor for subject's action for this action
923 // Return value: 0 = impossible, >0 = factor
924 static float getSuspectNearness(bool is_guess, v3s16 suspect_p, time_t suspect_t,
925                                 v3s16 action_p, time_t action_t)
926 {
927         // Suspect cannot cause things in the past
928         if (action_t < suspect_t) {
929                 return 0;        // 0 = cannot be
930         }
931         // Start from 100
932         int f = 100;
933         // Distance (1 node = -x points)
934         f -= POINTS_PER_NODE * intToFloat(suspect_p, 1).getDistanceFrom(intToFloat(action_p, 1));
935         // Time (1 second = -x points)
936         f -= 1 * (action_t - suspect_t);
937         // If is a guess, halve the points
938         if (is_guess) {
939                 f *= 0.5;
940         }
941         // Limit to 0
942         if (f < 0) {
943                 f = 0;
944         }
945         return f;
946 }
947 class RollbackManager: public IRollbackManager
948 {
949 public:
950         // IRollbackManager interface
951         void reportAction(const RollbackAction &action_) {
952                 // Ignore if not important
953                 if (!action_.isImportant(m_gamedef)) {
954                         return;
955                 }
956
957                 RollbackAction action = action_;
958                 action.unix_time = time(0);
959
960                 // Figure out actor
961                 action.actor = m_current_actor;
962                 action.actor_is_guess = m_current_actor_is_guess;
963
964                 if (action.actor.empty()) { // If actor is not known, find out suspect or cancel
965                         v3s16 p;
966                         if (!action.getPosition(&p)) {
967                                 return;
968                         }
969
970                         action.actor = getSuspect(p, 83, 1);
971                         if (action.actor.empty()) {
972                                 return;
973                         }
974
975                         action.actor_is_guess = true;
976                 }
977
978                 infostream
979                                 << "RollbackManager::reportAction():"
980                                 << " time=" << action.unix_time
981                                 << " actor=\"" << action.actor << "\""
982                                 << (action.actor_is_guess ? " (guess)" : "")
983                                 << " action=" << action.toString()
984                                 << std::endl;
985                 addAction(action);
986         }
987
988         std::string getActor() {
989                 return m_current_actor;
990         }
991
992         bool isActorGuess() {
993                 return m_current_actor_is_guess;
994         }
995
996         void setActor(const std::string &actor, bool is_guess) {
997                 m_current_actor = actor;
998                 m_current_actor_is_guess = is_guess;
999         }
1000
1001         std::string getSuspect(v3s16 p, float nearness_shortcut, float min_nearness) {
1002                 if (m_current_actor != "") {
1003                         return m_current_actor;
1004                 }
1005                 int cur_time = time(0);
1006                 time_t first_time = cur_time - (100 - min_nearness);
1007                 RollbackAction likely_suspect;
1008                 float likely_suspect_nearness = 0;
1009                 for (std::list<RollbackAction>::const_reverse_iterator
1010                      i = m_action_latest_buffer.rbegin();
1011                      i != m_action_latest_buffer.rend(); i++) {
1012                         if (i->unix_time < first_time) {
1013                                 break;
1014                         }
1015                         if (i->actor == "") {
1016                                 continue;
1017                         }
1018                         // Find position of suspect or continue
1019                         v3s16 suspect_p;
1020                         if (!i->getPosition(&suspect_p)) {
1021                                 continue;
1022                         }
1023                         float f = getSuspectNearness(i->actor_is_guess, suspect_p,
1024                                                      i->unix_time, p, cur_time);
1025                         if (f >= min_nearness && f > likely_suspect_nearness) {
1026                                 likely_suspect_nearness = f;
1027                                 likely_suspect = *i;
1028                                 if (likely_suspect_nearness >= nearness_shortcut) {
1029                                         break;
1030                                 }
1031                         }
1032                 }
1033                 // No likely suspect was found
1034                 if (likely_suspect_nearness == 0) {
1035                         return "";
1036                 }
1037                 // Likely suspect was found
1038                 return likely_suspect.actor;
1039         }
1040
1041         void flush() {
1042                 infostream << "RollbackManager::flush()" << std::endl;
1043
1044                 sqlite3_exec(dbh, "BEGIN", NULL, NULL, NULL);
1045
1046                 std::list<RollbackAction>::const_iterator iter;
1047
1048                 for (iter  = m_action_todisk_buffer.begin();
1049                      iter != m_action_todisk_buffer.end();
1050                      iter++) {
1051                         if (iter->actor == "") {
1052                                 continue;
1053                         }
1054
1055                         SQL_registerRow(actionRowFromRollbackAction(*iter));
1056                 }
1057
1058                 sqlite3_exec(dbh, "COMMIT", NULL, NULL, NULL);
1059                 m_action_todisk_buffer.clear();
1060         }
1061
1062         RollbackManager(const std::string &filepath, IGameDef *gamedef):
1063                 m_filepath(filepath),
1064                 m_gamedef(gamedef),
1065                 m_current_actor_is_guess(false) {
1066                 infostream
1067                                 << "RollbackManager::RollbackManager(" << filepath << ")"
1068                                 << std::endl;
1069
1070                 // Operate correctly in case of still being given rollback.txt as filepath
1071                 std::string directory   =  filepath.substr(0, filepath.rfind(DIR_DELIM) + 1);
1072                 std::string filenameOld =  filepath.substr(filepath.rfind(DIR_DELIM) + 1);
1073                 std::string filenameNew = (filenameOld == "rollback.txt") ? "rollback.sqlite" :
1074                                           filenameOld;
1075                 std::string filenameTXT =  directory + "rollback.txt";
1076                 std::string migratingFlag = filepath + ".migrating";
1077
1078                 infostream << "Directory: " << directory   << std::endl;
1079                 infostream << "CheckFor:  " << filenameTXT << std::endl;
1080                 infostream << "FileOld:   " << filenameOld << std::endl;
1081                 infostream << "FileNew:   " << filenameNew << std::endl;
1082
1083                 dbp = directory + filenameNew;
1084
1085                 if ((fs::PathExists(filenameTXT) && fs::PathExists(migratingFlag)) ||
1086                     (fs::PathExists(filenameTXT) && !fs::PathExists(dbp))) {
1087                         std::ofstream of(migratingFlag.c_str());
1088                         TXT_migrate(filenameTXT);
1089                         fs::DeleteSingleFileOrEmptyDirectory(migratingFlag);
1090                 }
1091
1092                 SQL_databaseCheck();
1093         }
1094 #define FINALIZE_STATEMENT(statement)                                          \
1095         if ( statement )                                                           \
1096                 rc = sqlite3_finalize(statement);                                      \
1097         if ( rc != SQLITE_OK )                                                     \
1098                 errorstream << "RollbackManager::~RollbackManager():"                  \
1099                         << "Failed to finalize: " << #statement << ": rc=" << rc << std::endl;
1100
1101         ~RollbackManager() {
1102                 infostream << "RollbackManager::~RollbackManager()" << std::endl;
1103                 flush();
1104
1105                 int rc = SQLITE_OK;
1106
1107                 FINALIZE_STATEMENT(dbs_insert)
1108                 FINALIZE_STATEMENT(dbs_replace)
1109                 FINALIZE_STATEMENT(dbs_select)
1110                 FINALIZE_STATEMENT(dbs_select_range)
1111                 FINALIZE_STATEMENT(dbs_select_withActor)
1112                 FINALIZE_STATEMENT(dbs_knownActor_select)
1113                 FINALIZE_STATEMENT(dbs_knownActor_insert)
1114                 FINALIZE_STATEMENT(dbs_knownNode_select)
1115                 FINALIZE_STATEMENT(dbs_knownNode_insert)
1116
1117                 if(dbh)
1118                         rc = sqlite3_close(dbh);
1119
1120                 if (rc != SQLITE_OK) {
1121                         errorstream << "RollbackManager::~RollbackManager(): "
1122                                         << "Failed to close database: rc=" << rc << std::endl;
1123                 }
1124         }
1125
1126         void addAction(const RollbackAction &action) {
1127                 m_action_todisk_buffer.push_back(action);
1128                 m_action_latest_buffer.push_back(action);
1129
1130                 // Flush to disk sometimes
1131                 if (m_action_todisk_buffer.size() >= 500) {
1132                         flush();
1133                 }
1134         }
1135
1136         std::list<RollbackAction> getEntriesSince(time_t first_time) {
1137                 infostream
1138                                 << "RollbackManager::getEntriesSince(" << first_time << ")"
1139                                 << std::endl;
1140
1141                 flush();
1142
1143                 std::list<RollbackAction> result = SQL_getActionsSince(first_time);
1144
1145                 return result;
1146         }
1147
1148         std::list<RollbackAction> getNodeActors(v3s16 pos, int range, time_t seconds, int limit) {
1149                 time_t cur_time = time(0);
1150                 time_t first_time = cur_time - seconds;
1151
1152                 return SQL_getActionsSince_range(first_time, pos, range, limit);
1153         }
1154
1155         std::list<RollbackAction> getRevertActions(const std::string &actor_filter,
1156                         time_t seconds) {
1157                 infostream
1158                                 << "RollbackManager::getRevertActions(" << actor_filter
1159                                 << ", " << seconds << ")"
1160                                 << std::endl;
1161
1162                 // Figure out time
1163                 time_t cur_time = time(0);
1164                 time_t first_time = cur_time - seconds;
1165
1166                 flush();
1167
1168                 std::list<RollbackAction> result = SQL_getActionsSince(first_time, actor_filter);
1169
1170                 return result;
1171         }
1172 private:
1173         std::string m_filepath;
1174         IGameDef *m_gamedef;
1175         std::string m_current_actor;
1176         bool m_current_actor_is_guess;
1177         std::list<RollbackAction> m_action_todisk_buffer;
1178         std::list<RollbackAction> m_action_latest_buffer;
1179 };
1180
1181 IRollbackManager *createRollbackManager(const std::string &filepath, IGameDef *gamedef)
1182 {
1183         return new RollbackManager(filepath, gamedef);
1184 }
1185