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.
28 #include "util/serialize.h"
29 #include "util/string.h"
30 #include "util/numeric.h"
31 #include "inventorymanager.h" // deserializing InventoryLocations
35 #define POINTS_PER_NODE (16.0)
37 #define SQLRES(f, good) \
39 throw FileNotGoodException(std::string("RollbackManager: " \
40 "SQLite3 error (" __FILE__ ":" TOSTRING(__LINE__) \
41 "): ") + sqlite3_errmsg(db)); \
43 #define SQLOK(f) SQLRES(f, SQLITE_OK)
45 #define SQLOK_ERRSTREAM(s, m) \
46 if ((s) != SQLITE_OK) { \
47 errorstream << "RollbackManager: " << (m) << ": " \
48 << sqlite3_errmsg(db) << std::endl; \
51 #define FINALIZE_STATEMENT(statement) \
52 SQLOK_ERRSTREAM(sqlite3_finalize(statement), "Failed to finalize " #statement)
54 class ItemStackRow
: public ItemStack
{
56 ItemStackRow
& operator = (const ItemStack
& other
)
58 *static_cast<ItemStack
*>(this) = other
;
70 std::string location
, list
;
76 int oldParam1
, oldParam2
;
79 int newParam1
, newParam2
;
92 RollbackManager::RollbackManager(const std::string
& world_path
,
93 IGameDef
* gamedef_
) :
96 verbosestream
<< "RollbackManager::RollbackManager(" << world_path
99 std::string txt_filename
= world_path
+ DIR_DELIM
"rollback.txt";
100 std::string migrating_flag
= txt_filename
+ ".migrating";
101 database_path
= world_path
+ DIR_DELIM
"rollback.sqlite";
103 bool created
= initDatabase();
105 if (fs::PathExists(txt_filename
) && (created
||
106 fs::PathExists(migrating_flag
))) {
107 std::ofstream
of(migrating_flag
.c_str());
109 migrate(txt_filename
);
110 fs::DeleteSingleFileOrEmptyDirectory(migrating_flag
);
115 RollbackManager::~RollbackManager()
119 FINALIZE_STATEMENT(stmt_insert
);
120 FINALIZE_STATEMENT(stmt_replace
);
121 FINALIZE_STATEMENT(stmt_select
);
122 FINALIZE_STATEMENT(stmt_select_range
);
123 FINALIZE_STATEMENT(stmt_select_withActor
);
124 FINALIZE_STATEMENT(stmt_knownActor_select
);
125 FINALIZE_STATEMENT(stmt_knownActor_insert
);
126 FINALIZE_STATEMENT(stmt_knownNode_select
);
127 FINALIZE_STATEMENT(stmt_knownNode_insert
);
129 SQLOK_ERRSTREAM(sqlite3_close(db
), "Could not close db");
133 void RollbackManager::registerNewActor(const int id
, const std::string
&name
)
135 Entity actor
= {id
, name
};
136 knownActors
.push_back(actor
);
140 void RollbackManager::registerNewNode(const int id
, const std::string
&name
)
142 Entity node
= {id
, name
};
143 knownNodes
.push_back(node
);
147 int RollbackManager::getActorId(const std::string
&name
)
149 for (std::vector
<Entity
>::const_iterator iter
= knownActors
.begin();
150 iter
!= knownActors
.end(); ++iter
) {
151 if (iter
->name
== name
) {
156 SQLOK(sqlite3_bind_text(stmt_knownActor_insert
, 1, name
.c_str(), name
.size(), NULL
));
157 SQLRES(sqlite3_step(stmt_knownActor_insert
), SQLITE_DONE
);
158 SQLOK(sqlite3_reset(stmt_knownActor_insert
));
160 int id
= sqlite3_last_insert_rowid(db
);
161 registerNewActor(id
, name
);
167 int RollbackManager::getNodeId(const std::string
&name
)
169 for (std::vector
<Entity
>::const_iterator iter
= knownNodes
.begin();
170 iter
!= knownNodes
.end(); ++iter
) {
171 if (iter
->name
== name
) {
176 SQLOK(sqlite3_bind_text(stmt_knownNode_insert
, 1, name
.c_str(), name
.size(), NULL
));
177 SQLRES(sqlite3_step(stmt_knownNode_insert
), SQLITE_DONE
);
178 SQLOK(sqlite3_reset(stmt_knownNode_insert
));
180 int id
= sqlite3_last_insert_rowid(db
);
181 registerNewNode(id
, name
);
187 const char * RollbackManager::getActorName(const int id
)
189 for (std::vector
<Entity
>::const_iterator iter
= knownActors
.begin();
190 iter
!= knownActors
.end(); ++iter
) {
191 if (iter
->id
== id
) {
192 return iter
->name
.c_str();
200 const char * RollbackManager::getNodeName(const int id
)
202 for (std::vector
<Entity
>::const_iterator iter
= knownNodes
.begin();
203 iter
!= knownNodes
.end(); ++iter
) {
204 if (iter
->id
== id
) {
205 return iter
->name
.c_str();
213 bool RollbackManager::createTables()
215 SQLOK(sqlite3_exec(db
,
216 "CREATE TABLE IF NOT EXISTS `actor` (\n"
217 " `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,\n"
218 " `name` TEXT NOT NULL\n"
220 "CREATE TABLE IF NOT EXISTS `node` (\n"
221 " `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,\n"
222 " `name` TEXT NOT NULL\n"
224 "CREATE TABLE IF NOT EXISTS `action` (\n"
225 " `id` INTEGER PRIMARY KEY AUTOINCREMENT,\n"
226 " `actor` INTEGER NOT NULL,\n"
227 " `timestamp` TIMESTAMP NOT NULL,\n"
228 " `type` INTEGER NOT NULL,\n"
230 " `index` INTEGER,\n"
232 " `stackNode` INTEGER,\n"
233 " `stackQuantity` INTEGER,\n"
234 " `nodeMeta` INTEGER,\n"
238 " `oldNode` INTEGER,\n"
239 " `oldParam1` INTEGER,\n"
240 " `oldParam2` INTEGER,\n"
242 " `newNode` INTEGER,\n"
243 " `newParam1` INTEGER,\n"
244 " `newParam2` INTEGER,\n"
246 " `guessedActor` INTEGER,\n"
247 " FOREIGN KEY (`actor`) REFERENCES `actor`(`id`),\n"
248 " FOREIGN KEY (`stackNode`) REFERENCES `node`(`id`),\n"
249 " FOREIGN KEY (`oldNode`) REFERENCES `node`(`id`),\n"
250 " FOREIGN KEY (`newNode`) REFERENCES `node`(`id`)\n"
252 "CREATE INDEX IF NOT EXISTS `actionIndex` ON `action`(`x`,`y`,`z`,`timestamp`,`actor`);\n",
254 verbosestream
<< "SQL Rollback: SQLite3 database structure was created" << std::endl
;
260 bool RollbackManager::initDatabase()
262 verbosestream
<< "RollbackManager: Database connection setup" << std::endl
;
264 bool needs_create
= !fs::PathExists(database_path
);
265 SQLOK(sqlite3_open_v2(database_path
.c_str(), &db
,
266 SQLITE_OPEN_READWRITE
| SQLITE_OPEN_CREATE
, NULL
));
272 SQLOK(sqlite3_prepare_v2(db
,
273 "INSERT INTO `action` (\n"
274 " `actor`, `timestamp`, `type`,\n"
275 " `list`, `index`, `add`, `stackNode`, `stackQuantity`, `nodeMeta`,\n"
277 " `oldNode`, `oldParam1`, `oldParam2`, `oldMeta`,\n"
278 " `newNode`, `newParam1`, `newParam2`, `newMeta`,\n"
282 " ?, ?, ?, ?, ?, ?,\n"
288 -1, &stmt_insert
, NULL
));
290 SQLOK(sqlite3_prepare_v2(db
,
291 "REPLACE INTO `action` (\n"
292 " `actor`, `timestamp`, `type`,\n"
293 " `list`, `index`, `add`, `stackNode`, `stackQuantity`, `nodeMeta`,\n"
295 " `oldNode`, `oldParam1`, `oldParam2`, `oldMeta`,\n"
296 " `newNode`, `newParam1`, `newParam2`, `newMeta`,\n"
297 " `guessedActor`, `id`\n"
300 " ?, ?, ?, ?, ?, ?,\n"
306 -1, &stmt_replace
, NULL
));
308 SQLOK(sqlite3_prepare_v2(db
,
310 " `actor`, `timestamp`, `type`,\n"
311 " `list`, `index`, `add`, `stackNode`, `stackQuantity`, `nodemeta`,\n"
313 " `oldNode`, `oldParam1`, `oldParam2`, `oldMeta`,\n"
314 " `newNode`, `newParam1`, `newParam2`, `newMeta`,\n"
317 " WHERE `timestamp` >= ?\n"
318 " ORDER BY `timestamp` DESC, `id` DESC",
319 -1, &stmt_select
, NULL
));
321 SQLOK(sqlite3_prepare_v2(db
,
323 " `actor`, `timestamp`, `type`,\n"
324 " `list`, `index`, `add`, `stackNode`, `stackQuantity`, `nodemeta`,\n"
326 " `oldNode`, `oldParam1`, `oldParam2`, `oldMeta`,\n"
327 " `newNode`, `newParam1`, `newParam2`, `newMeta`,\n"
330 "WHERE `timestamp` >= ?\n"
331 " AND `x` IS NOT NULL\n"
332 " AND `y` IS NOT NULL\n"
333 " AND `z` IS NOT NULL\n"
334 " AND `x` BETWEEN ? AND ?\n"
335 " AND `y` BETWEEN ? AND ?\n"
336 " AND `z` BETWEEN ? AND ?\n"
337 "ORDER BY `timestamp` DESC, `id` DESC\n"
339 -1, &stmt_select_range
, NULL
));
341 SQLOK(sqlite3_prepare_v2(db
,
343 " `actor`, `timestamp`, `type`,\n"
344 " `list`, `index`, `add`, `stackNode`, `stackQuantity`, `nodemeta`,\n"
346 " `oldNode`, `oldParam1`, `oldParam2`, `oldMeta`,\n"
347 " `newNode`, `newParam1`, `newParam2`, `newMeta`,\n"
350 "WHERE `timestamp` >= ?\n"
352 "ORDER BY `timestamp` DESC, `id` DESC\n",
353 -1, &stmt_select_withActor
, NULL
));
355 SQLOK(sqlite3_prepare_v2(db
, "SELECT `id`, `name` FROM `actor`",
356 -1, &stmt_knownActor_select
, NULL
));
358 SQLOK(sqlite3_prepare_v2(db
, "INSERT INTO `actor` (`name`) VALUES (?)",
359 -1, &stmt_knownActor_insert
, NULL
));
361 SQLOK(sqlite3_prepare_v2(db
, "SELECT `id`, `name` FROM `node`",
362 -1, &stmt_knownNode_select
, NULL
));
364 SQLOK(sqlite3_prepare_v2(db
, "INSERT INTO `node` (`name`) VALUES (?)",
365 -1, &stmt_knownNode_insert
, NULL
));
367 verbosestream
<< "SQL prepared statements setup correctly" << std::endl
;
369 while (sqlite3_step(stmt_knownActor_select
) == SQLITE_ROW
) {
371 sqlite3_column_int(stmt_knownActor_select
, 0),
372 reinterpret_cast<const char *>(sqlite3_column_text(stmt_knownActor_select
, 1))
375 SQLOK(sqlite3_reset(stmt_knownActor_select
));
377 while (sqlite3_step(stmt_knownNode_select
) == SQLITE_ROW
) {
379 sqlite3_column_int(stmt_knownNode_select
, 0),
380 reinterpret_cast<const char *>(sqlite3_column_text(stmt_knownNode_select
, 1))
383 SQLOK(sqlite3_reset(stmt_knownNode_select
));
389 bool RollbackManager::registerRow(const ActionRow
& row
)
391 sqlite3_stmt
* stmt_do
= (row
.id
) ? stmt_replace
: stmt_insert
;
393 bool nodeMeta
= false;
395 SQLOK(sqlite3_bind_int (stmt_do
, 1, row
.actor
));
396 SQLOK(sqlite3_bind_int64(stmt_do
, 2, row
.timestamp
));
397 SQLOK(sqlite3_bind_int (stmt_do
, 3, row
.type
));
399 if (row
.type
== RollbackAction::TYPE_MODIFY_INVENTORY_STACK
) {
400 const std::string
& loc
= row
.location
;
401 nodeMeta
= (loc
.substr(0, 9) == "nodemeta:");
403 SQLOK(sqlite3_bind_text(stmt_do
, 4, row
.list
.c_str(), row
.list
.size(), NULL
));
404 SQLOK(sqlite3_bind_int (stmt_do
, 5, row
.index
));
405 SQLOK(sqlite3_bind_int (stmt_do
, 6, row
.add
));
406 SQLOK(sqlite3_bind_int (stmt_do
, 7, row
.stack
.id
));
407 SQLOK(sqlite3_bind_int (stmt_do
, 8, row
.stack
.count
));
408 SQLOK(sqlite3_bind_int (stmt_do
, 9, (int) nodeMeta
));
411 std::string::size_type p1
, p2
;
412 p1
= loc
.find(':') + 1;
414 std::string x
= loc
.substr(p1
, p2
- p1
);
416 p2
= loc
.find(',', p1
);
417 std::string y
= loc
.substr(p1
, p2
- p1
);
418 std::string z
= loc
.substr(p2
+ 1);
419 SQLOK(sqlite3_bind_int(stmt_do
, 10, atoi(x
.c_str())));
420 SQLOK(sqlite3_bind_int(stmt_do
, 11, atoi(y
.c_str())));
421 SQLOK(sqlite3_bind_int(stmt_do
, 12, atoi(z
.c_str())));
424 SQLOK(sqlite3_bind_null(stmt_do
, 4));
425 SQLOK(sqlite3_bind_null(stmt_do
, 5));
426 SQLOK(sqlite3_bind_null(stmt_do
, 6));
427 SQLOK(sqlite3_bind_null(stmt_do
, 7));
428 SQLOK(sqlite3_bind_null(stmt_do
, 8));
429 SQLOK(sqlite3_bind_null(stmt_do
, 9));
432 if (row
.type
== RollbackAction::TYPE_SET_NODE
) {
433 SQLOK(sqlite3_bind_int (stmt_do
, 10, row
.x
));
434 SQLOK(sqlite3_bind_int (stmt_do
, 11, row
.y
));
435 SQLOK(sqlite3_bind_int (stmt_do
, 12, row
.z
));
436 SQLOK(sqlite3_bind_int (stmt_do
, 13, row
.oldNode
));
437 SQLOK(sqlite3_bind_int (stmt_do
, 14, row
.oldParam1
));
438 SQLOK(sqlite3_bind_int (stmt_do
, 15, row
.oldParam2
));
439 SQLOK(sqlite3_bind_text(stmt_do
, 16, row
.oldMeta
.c_str(), row
.oldMeta
.size(), NULL
));
440 SQLOK(sqlite3_bind_int (stmt_do
, 17, row
.newNode
));
441 SQLOK(sqlite3_bind_int (stmt_do
, 18, row
.newParam1
));
442 SQLOK(sqlite3_bind_int (stmt_do
, 19, row
.newParam2
));
443 SQLOK(sqlite3_bind_text(stmt_do
, 20, row
.newMeta
.c_str(), row
.newMeta
.size(), NULL
));
444 SQLOK(sqlite3_bind_int (stmt_do
, 21, row
.guessed
? 1 : 0));
447 SQLOK(sqlite3_bind_null(stmt_do
, 10));
448 SQLOK(sqlite3_bind_null(stmt_do
, 11));
449 SQLOK(sqlite3_bind_null(stmt_do
, 12));
451 SQLOK(sqlite3_bind_null(stmt_do
, 13));
452 SQLOK(sqlite3_bind_null(stmt_do
, 14));
453 SQLOK(sqlite3_bind_null(stmt_do
, 15));
454 SQLOK(sqlite3_bind_null(stmt_do
, 16));
455 SQLOK(sqlite3_bind_null(stmt_do
, 17));
456 SQLOK(sqlite3_bind_null(stmt_do
, 18));
457 SQLOK(sqlite3_bind_null(stmt_do
, 19));
458 SQLOK(sqlite3_bind_null(stmt_do
, 20));
459 SQLOK(sqlite3_bind_null(stmt_do
, 21));
463 SQLOK(sqlite3_bind_int(stmt_do
, 22, row
.id
));
466 int written
= sqlite3_step(stmt_do
);
468 SQLOK(sqlite3_reset(stmt_do
));
470 return written
== SQLITE_DONE
;
474 const std::list
<ActionRow
> RollbackManager::actionRowsFromSelect(sqlite3_stmt
* stmt
)
476 std::list
<ActionRow
> rows
;
477 const unsigned char * text
;
480 while (sqlite3_step(stmt
) == SQLITE_ROW
) {
483 row
.actor
= sqlite3_column_int (stmt
, 0);
484 row
.timestamp
= sqlite3_column_int64(stmt
, 1);
485 row
.type
= sqlite3_column_int (stmt
, 2);
487 if (row
.type
== RollbackAction::TYPE_MODIFY_INVENTORY_STACK
) {
488 text
= sqlite3_column_text (stmt
, 3);
489 size
= sqlite3_column_bytes(stmt
, 3);
490 row
.list
= std::string(reinterpret_cast<const char*>(text
), size
);
491 row
.index
= sqlite3_column_int(stmt
, 4);
492 row
.add
= sqlite3_column_int(stmt
, 5);
493 row
.stack
.id
= sqlite3_column_int(stmt
, 6);
494 row
.stack
.count
= sqlite3_column_int(stmt
, 7);
495 row
.nodeMeta
= sqlite3_column_int(stmt
, 8);
498 if (row
.type
== RollbackAction::TYPE_SET_NODE
|| row
.nodeMeta
) {
499 row
.x
= sqlite3_column_int(stmt
, 9);
500 row
.y
= sqlite3_column_int(stmt
, 10);
501 row
.z
= sqlite3_column_int(stmt
, 11);
504 if (row
.type
== RollbackAction::TYPE_SET_NODE
) {
505 row
.oldNode
= sqlite3_column_int(stmt
, 12);
506 row
.oldParam1
= sqlite3_column_int(stmt
, 13);
507 row
.oldParam2
= sqlite3_column_int(stmt
, 14);
508 text
= sqlite3_column_text (stmt
, 15);
509 size
= sqlite3_column_bytes(stmt
, 15);
510 row
.oldMeta
= std::string(reinterpret_cast<const char*>(text
), size
);
511 row
.newNode
= sqlite3_column_int(stmt
, 16);
512 row
.newParam1
= sqlite3_column_int(stmt
, 17);
513 row
.newParam2
= sqlite3_column_int(stmt
, 18);
514 text
= sqlite3_column_text(stmt
, 19);
515 size
= sqlite3_column_bytes(stmt
, 19);
516 row
.newMeta
= std::string(reinterpret_cast<const char*>(text
), size
);
517 row
.guessed
= sqlite3_column_int(stmt
, 20);
521 row
.location
= "nodemeta:";
522 row
.location
+= itos(row
.x
);
524 row
.location
+= itos(row
.y
);
526 row
.location
+= itos(row
.z
);
528 row
.location
= getActorName(row
.actor
);
534 SQLOK(sqlite3_reset(stmt
));
540 ActionRow
RollbackManager::actionRowFromRollbackAction(const RollbackAction
& action
)
545 row
.actor
= getActorId(action
.actor
);
546 row
.timestamp
= action
.unix_time
;
547 row
.type
= action
.type
;
549 if (row
.type
== RollbackAction::TYPE_MODIFY_INVENTORY_STACK
) {
550 row
.location
= action
.inventory_location
;
551 row
.list
= action
.inventory_list
;
552 row
.index
= action
.inventory_index
;
553 row
.add
= action
.inventory_add
;
554 row
.stack
= action
.inventory_stack
;
555 row
.stack
.id
= getNodeId(row
.stack
.name
);
560 row
.oldNode
= getNodeId(action
.n_old
.name
);
561 row
.oldParam1
= action
.n_old
.param1
;
562 row
.oldParam2
= action
.n_old
.param2
;
563 row
.oldMeta
= action
.n_old
.meta
;
564 row
.newNode
= getNodeId(action
.n_new
.name
);
565 row
.newParam1
= action
.n_new
.param1
;
566 row
.newParam2
= action
.n_new
.param2
;
567 row
.newMeta
= action
.n_new
.meta
;
568 row
.guessed
= action
.actor_is_guess
;
575 const std::list
<RollbackAction
> RollbackManager::rollbackActionsFromActionRows(
576 const std::list
<ActionRow
> & rows
)
578 std::list
<RollbackAction
> actions
;
580 for (const ActionRow
&row
: rows
) {
581 RollbackAction action
;
582 action
.actor
= (row
.actor
) ? getActorName(row
.actor
) : "";
583 action
.unix_time
= row
.timestamp
;
584 action
.type
= static_cast<RollbackAction::Type
>(row
.type
);
586 switch (action
.type
) {
587 case RollbackAction::TYPE_MODIFY_INVENTORY_STACK
:
588 action
.inventory_location
= row
.location
;
589 action
.inventory_list
= row
.list
;
590 action
.inventory_index
= row
.index
;
591 action
.inventory_add
= row
.add
;
592 action
.inventory_stack
= row
.stack
;
593 if (action
.inventory_stack
.name
.empty()) {
594 action
.inventory_stack
.name
= getNodeName(row
.stack
.id
);
598 case RollbackAction::TYPE_SET_NODE
:
599 action
.p
= v3s16(row
.x
, row
.y
, row
.z
);
600 action
.n_old
.name
= getNodeName(row
.oldNode
);
601 action
.n_old
.param1
= row
.oldParam1
;
602 action
.n_old
.param2
= row
.oldParam2
;
603 action
.n_old
.meta
= row
.oldMeta
;
604 action
.n_new
.name
= getNodeName(row
.newNode
);
605 action
.n_new
.param1
= row
.newParam1
;
606 action
.n_new
.param2
= row
.newParam2
;
607 action
.n_new
.meta
= row
.newMeta
;
615 actions
.push_back(action
);
622 const std::list
<ActionRow
> RollbackManager::getRowsSince(time_t firstTime
, const std::string
& actor
)
624 sqlite3_stmt
*stmt_stmt
= actor
.empty() ? stmt_select
: stmt_select_withActor
;
625 sqlite3_bind_int64(stmt_stmt
, 1, firstTime
);
627 if (!actor
.empty()) {
628 sqlite3_bind_int(stmt_stmt
, 2, getActorId(actor
));
631 const std::list
<ActionRow
> & rows
= actionRowsFromSelect(stmt_stmt
);
632 sqlite3_reset(stmt_stmt
);
638 const std::list
<ActionRow
> RollbackManager::getRowsSince_range(
639 time_t start_time
, v3s16 p
, int range
, int limit
)
642 sqlite3_bind_int64(stmt_select_range
, 1, start_time
);
643 sqlite3_bind_int (stmt_select_range
, 2, static_cast<int>(p
.X
- range
));
644 sqlite3_bind_int (stmt_select_range
, 3, static_cast<int>(p
.X
+ range
));
645 sqlite3_bind_int (stmt_select_range
, 4, static_cast<int>(p
.Y
- range
));
646 sqlite3_bind_int (stmt_select_range
, 5, static_cast<int>(p
.Y
+ range
));
647 sqlite3_bind_int (stmt_select_range
, 6, static_cast<int>(p
.Z
- range
));
648 sqlite3_bind_int (stmt_select_range
, 7, static_cast<int>(p
.Z
+ range
));
649 sqlite3_bind_int (stmt_select_range
, 8, limit
);
651 const std::list
<ActionRow
> & rows
= actionRowsFromSelect(stmt_select_range
);
652 sqlite3_reset(stmt_select_range
);
658 const std::list
<RollbackAction
> RollbackManager::getActionsSince_range(
659 time_t start_time
, v3s16 p
, int range
, int limit
)
661 return rollbackActionsFromActionRows(getRowsSince_range(start_time
, p
, range
, limit
));
665 const std::list
<RollbackAction
> RollbackManager::getActionsSince(
666 time_t start_time
, const std::string
& actor
)
668 return rollbackActionsFromActionRows(getRowsSince(start_time
, actor
));
672 void RollbackManager::migrate(const std::string
& file_path
)
674 std::cout
<< "Migrating from rollback.txt to rollback.sqlite." << std::endl
;
676 std::ifstream
fh(file_path
.c_str(), std::ios::in
| std::ios::ate
);
678 throw FileNotGoodException("Unable to open rollback.txt");
681 std::streampos file_size
= fh
.tellg();
683 if (file_size
< 10) {
684 errorstream
<< "Empty rollback log." << std::endl
;
690 sqlite3_stmt
*stmt_begin
;
691 sqlite3_stmt
*stmt_commit
;
692 SQLOK(sqlite3_prepare_v2(db
, "BEGIN", -1, &stmt_begin
, NULL
));
693 SQLOK(sqlite3_prepare_v2(db
, "COMMIT", -1, &stmt_commit
, NULL
));
697 time_t start
= time(0);
699 SQLRES(sqlite3_step(stmt_begin
), SQLITE_DONE
);
700 sqlite3_reset(stmt_begin
);
706 std::getline(fh
, bit
, ' ');
708 if (!atoi(bit
.c_str())) {
709 std::getline(fh
, bit
);
712 row
.timestamp
= atoi(bit
.c_str());
715 row
.actor
= getActorId(deSerializeJsonString(fh
));
717 // Get the action type
718 std::getline(fh
, bit
, '[');
719 std::getline(fh
, bit
, ' ');
721 if (bit
== "modify_inventory_stack") {
722 row
.type
= RollbackAction::TYPE_MODIFY_INVENTORY_STACK
;
723 row
.location
= trim(deSerializeJsonString(fh
));
724 std::getline(fh
, bit
, ' ');
725 row
.list
= trim(deSerializeJsonString(fh
));
726 std::getline(fh
, bit
, ' ');
727 std::getline(fh
, bit
, ' ');
728 row
.index
= atoi(trim(bit
).c_str());
729 std::getline(fh
, bit
, ' ');
730 row
.add
= (int)(trim(bit
) == "add");
731 row
.stack
.deSerialize(deSerializeJsonString(fh
));
732 row
.stack
.id
= getNodeId(row
.stack
.name
);
733 std::getline(fh
, bit
);
734 } else if (bit
== "set_node") {
735 row
.type
= RollbackAction::TYPE_SET_NODE
;
736 std::getline(fh
, bit
, '(');
737 std::getline(fh
, bit
, ',');
738 row
.x
= atoi(trim(bit
).c_str());
739 std::getline(fh
, bit
, ',');
740 row
.y
= atoi(trim(bit
).c_str());
741 std::getline(fh
, bit
, ')');
742 row
.z
= atoi(trim(bit
).c_str());
743 std::getline(fh
, bit
, ' ');
744 row
.oldNode
= getNodeId(trim(deSerializeJsonString(fh
)));
745 std::getline(fh
, bit
, ' ');
746 std::getline(fh
, bit
, ' ');
747 row
.oldParam1
= atoi(trim(bit
).c_str());
748 std::getline(fh
, bit
, ' ');
749 row
.oldParam2
= atoi(trim(bit
).c_str());
750 row
.oldMeta
= trim(deSerializeJsonString(fh
));
751 std::getline(fh
, bit
, ' ');
752 row
.newNode
= getNodeId(trim(deSerializeJsonString(fh
)));
753 std::getline(fh
, bit
, ' ');
754 std::getline(fh
, bit
, ' ');
755 row
.newParam1
= atoi(trim(bit
).c_str());
756 std::getline(fh
, bit
, ' ');
757 row
.newParam2
= atoi(trim(bit
).c_str());
758 row
.newMeta
= trim(deSerializeJsonString(fh
));
759 std::getline(fh
, bit
, ' ');
760 std::getline(fh
, bit
, ' ');
761 std::getline(fh
, bit
);
762 row
.guessed
= (int)(trim(bit
) == "actor_is_guess");
764 errorstream
<< "Unrecognized rollback action type \""
765 << bit
<< "\"!" << std::endl
;
772 if (time(0) - t
>= 1) {
773 SQLRES(sqlite3_step(stmt_commit
), SQLITE_DONE
);
774 sqlite3_reset(stmt_commit
);
777 << " Done: " << static_cast<int>((static_cast<float>(fh
.tellg()) / static_cast<float>(file_size
)) * 100) << "%"
778 << " Speed: " << i
/ (t
- start
) << "/second \r" << std::flush
;
779 SQLRES(sqlite3_step(stmt_begin
), SQLITE_DONE
);
780 sqlite3_reset(stmt_begin
);
783 SQLRES(sqlite3_step(stmt_commit
), SQLITE_DONE
);
784 sqlite3_reset(stmt_commit
);
786 SQLOK(sqlite3_finalize(stmt_begin
));
787 SQLOK(sqlite3_finalize(stmt_commit
));
790 << " Done: 100% " << std::endl
791 << "Now you can delete the old rollback.txt file." << std::endl
;
795 // Get nearness factor for subject's action for this action
796 // Return value: 0 = impossible, >0 = factor
797 float RollbackManager::getSuspectNearness(bool is_guess
, v3s16 suspect_p
,
798 time_t suspect_t
, v3s16 action_p
, time_t action_t
)
800 // Suspect cannot cause things in the past
801 if (action_t
< suspect_t
) {
802 return 0; // 0 = cannot be
806 // Distance (1 node = -x points)
807 f
-= POINTS_PER_NODE
* intToFloat(suspect_p
, 1).getDistanceFrom(intToFloat(action_p
, 1));
808 // Time (1 second = -x points)
809 f
-= 1 * (action_t
- suspect_t
);
810 // If is a guess, halve the points
822 void RollbackManager::reportAction(const RollbackAction
&action_
)
824 // Ignore if not important
825 if (!action_
.isImportant(gamedef
)) {
829 RollbackAction action
= action_
;
830 action
.unix_time
= time(0);
833 action
.actor
= current_actor
;
834 action
.actor_is_guess
= current_actor_is_guess
;
836 if (action
.actor
.empty()) { // If actor is not known, find out suspect or cancel
838 if (!action
.getPosition(&p
)) {
842 action
.actor
= getSuspect(p
, 83, 1);
843 if (action
.actor
.empty()) {
847 action
.actor_is_guess
= true;
853 std::string
RollbackManager::getActor()
855 return current_actor
;
858 bool RollbackManager::isActorGuess()
860 return current_actor_is_guess
;
863 void RollbackManager::setActor(const std::string
& actor
, bool is_guess
)
865 current_actor
= actor
;
866 current_actor_is_guess
= is_guess
;
869 std::string
RollbackManager::getSuspect(v3s16 p
, float nearness_shortcut
,
872 if (!current_actor
.empty()) {
873 return current_actor
;
875 int cur_time
= time(0);
876 time_t first_time
= cur_time
- (100 - min_nearness
);
877 RollbackAction likely_suspect
;
878 float likely_suspect_nearness
= 0;
879 for (std::list
<RollbackAction
>::const_reverse_iterator
880 i
= action_latest_buffer
.rbegin();
881 i
!= action_latest_buffer
.rend(); ++i
) {
882 if (i
->unix_time
< first_time
) {
885 if (i
->actor
.empty()) {
888 // Find position of suspect or continue
890 if (!i
->getPosition(&suspect_p
)) {
893 float f
= getSuspectNearness(i
->actor_is_guess
, suspect_p
,
894 i
->unix_time
, p
, cur_time
);
895 if (f
>= min_nearness
&& f
> likely_suspect_nearness
) {
896 likely_suspect_nearness
= f
;
898 if (likely_suspect_nearness
>= nearness_shortcut
) {
903 // No likely suspect was found
904 if (likely_suspect_nearness
== 0) {
907 // Likely suspect was found
908 return likely_suspect
.actor
;
912 void RollbackManager::flush()
914 sqlite3_exec(db
, "BEGIN", NULL
, NULL
, NULL
);
916 std::list
<RollbackAction
>::const_iterator iter
;
918 for (iter
= action_todisk_buffer
.begin();
919 iter
!= action_todisk_buffer
.end();
921 if (iter
->actor
.empty()) {
925 registerRow(actionRowFromRollbackAction(*iter
));
928 sqlite3_exec(db
, "COMMIT", NULL
, NULL
, NULL
);
929 action_todisk_buffer
.clear();
933 void RollbackManager::addAction(const RollbackAction
& action
)
935 action_todisk_buffer
.push_back(action
);
936 action_latest_buffer
.push_back(action
);
938 // Flush to disk sometimes
939 if (action_todisk_buffer
.size() >= 500) {
944 std::list
<RollbackAction
> RollbackManager::getEntriesSince(time_t first_time
)
947 return getActionsSince(first_time
);
950 std::list
<RollbackAction
> RollbackManager::getNodeActors(v3s16 pos
, int range
,
951 time_t seconds
, int limit
)
954 time_t cur_time
= time(0);
955 time_t first_time
= cur_time
- seconds
;
957 return getActionsSince_range(first_time
, pos
, range
, limit
);
960 std::list
<RollbackAction
> RollbackManager::getRevertActions(
961 const std::string
&actor_filter
,
964 time_t cur_time
= time(0);
965 time_t first_time
= cur_time
- seconds
;
969 return getActionsSince(first_time
, actor_filter
);