Created
October 12, 2013 20:49
-
-
Save celeron55/6954775 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/src/rollback.cpp b/src/rollback.cpp | |
index e110068..34c4322 100644 | |
--- a/src/rollback.cpp | |
+++ b/src/rollback.cpp | |
@@ -29,11 +29,479 @@ | |
#include "util/string.h" | |
#include "util/numeric.h" | |
#include "inventorymanager.h" // deserializing InventoryLocations | |
+#include "sqlite3.h" | |
+#include "filesys.h" | |
#define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")" | |
#define POINTS_PER_NODE (16.0) | |
+std::string dbp; | |
+sqlite3* dbh; | |
+sqlite3_stmt* dbs_insert; | |
+sqlite3_stmt* dbs_replace; | |
+sqlite3_stmt* dbs_select; | |
+ | |
+bool SQL_createDatabase (void) | |
+{ | |
+ std::cout << "CreateDB:" << dbp << std::endl; | |
+ | |
+ int dbs = sqlite3_exec( | |
+ dbh | |
+ , "CREATE TABLE `action` (" | |
+ " `id` INTEGER PRIMARY KEY AUTOINCREMENT," | |
+ " `actor` TEXT NOT NULL," | |
+ " `timestamp` INTEGER NOT NULL," | |
+ " `type` INT NOT NULL," | |
+ " `list` TEXT," | |
+ " `index` INT," | |
+ " `add` INT," | |
+ " `stack` TEXT," | |
+ " `nodeMeta` INT," | |
+ " `x` INTEGER," | |
+ " `y` INTEGER," | |
+ " `z` INTEGER," | |
+ " `oldNode` TEXT," | |
+ " `oldParam1` INT," | |
+ " `oldParam2` INT," | |
+ " `oldMeta` TEXT," | |
+ " `newNode` TEXT," | |
+ " `newParam1` INT," | |
+ " `newParam2` INT," | |
+ " `newMeta` TEXT," | |
+ " `guessedActor` INTEGER" | |
+ ");" | |
+ "CREATE INDEX `actor` on `action` (`actor` ASC, `timestamp` ASC);" | |
+ , NULL, NULL, NULL | |
+ ); | |
+ if (dbs == SQLITE_ABORT) | |
+ throw FileNotGoodException("Could not create sqlite3 database structure"); | |
+ else | |
+ if (dbs != 0) | |
+ throw FileNotGoodException("SQL Rollback: Exec statement to create table structure returned a non-zero value"); | |
+ else | |
+ std::cout << "SQL Rollback: SQLite3 database structure was created" << std::endl; | |
+ | |
+ return true; | |
+} | |
+ | |
+void SQL_databaseCheck (void) | |
+{ | |
+ if (dbh) return; | |
+ //std::cout << "Database check" << std::endl; | |
+ | |
+ bool needsCreate = !fs::PathExists(dbp); | |
+ int dbo = sqlite3_open_v2(dbp.c_str(), &dbh, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL); | |
+ | |
+ if(dbo != SQLITE_OK) | |
+ { | |
+ std::cout | |
+ << "SQLROLLBACK: SQLite3 database failed to open: " | |
+ << sqlite3_errmsg(dbh) | |
+ << std::endl; | |
+ throw FileNotGoodException("Cannot open database file"); | |
+ } | |
+ | |
+ if (needsCreate) SQL_createDatabase(); | |
+ | |
+ int dbr; | |
+ | |
+ dbr = sqlite3_prepare_v2( | |
+ dbh | |
+ , "INSERT INTO `action`" | |
+ " ( `actor`, `timestamp`, `type`," | |
+ " `list`, `index`, `add`, `stack`, `nodeMeta`," | |
+ " `x`, `y`, `z`," | |
+ " `oldNode`, `oldParam1`, `oldParam2`, `oldMeta`," | |
+ " `newNode`, `newParam1`, `newParam2`, `newMeta`," | |
+ " `guessedActor`" | |
+ " )" | |
+ "VALUES" | |
+ " ( ?, ?, ?," | |
+ " ?, ?, ?, ?, ?," | |
+ " ?, ?, ?," | |
+ " ?, ?, ?, ?," | |
+ " ?, ?, ?, ?," | |
+ " ?" | |
+ " );" | |
+ , -1, &dbs_insert, NULL | |
+ ); | |
+ | |
+ if (dbr != SQLITE_OK) | |
+ throw FileNotGoodException(sqlite3_errmsg(dbh)); | |
+ | |
+ dbr = sqlite3_prepare_v2( | |
+ dbh | |
+ , "REPLACE INTO `action`" | |
+ " ( `actor`, `timestamp`, `type`," | |
+ " `list`, `index`, `add`, `stack`, `nodeMeta`," | |
+ " `x`, `y`, `z`," | |
+ " `oldNode`, `oldParam1`, `oldParam2`, `oldMeta`," | |
+ " `newNode`, `newParam1`, `newParam2`, `newMeta`," | |
+ " `guessedActor`, `id`" | |
+ " )" | |
+ "VALUES" | |
+ " ( ?, ?, ?," | |
+ " ?, ?, ?, ?, ?," | |
+ " ?, ?, ?," | |
+ " ?, ?, ?, ?," | |
+ " ?, ?, ?, ?," | |
+ " ?, ?" | |
+ " );" | |
+ , -1, &dbs_replace, NULL | |
+ ); | |
+ | |
+ if (dbr != SQLITE_OK) | |
+ throw FileNotGoodException(sqlite3_errmsg(dbh)); | |
+ | |
+ dbr = sqlite3_prepare_v2( | |
+ dbh | |
+ , "SELECT " | |
+ " `actor`, `timestamp`, `type`" | |
+ " , `list`, `index`, `add`, `stack`, `nodemeta`" | |
+ " , `x`, `y`, `z`" | |
+ " , `oldNode`, `oldParam1`, `oldParam2`, `oldMeta`" | |
+ " , `newNode`, `newParam1`, `newParam2`, `newMeta`" | |
+ " , `guessedActor`" | |
+ " FROM `action`" | |
+ " WHERE `actor` = ?" | |
+ " AND `timestamp` > ?" | |
+ " ORDER BY `timestamp` DESC" | |
+ , -1, &dbs_select, NULL | |
+ ); | |
+ | |
+ if (dbr != SQLITE_OK) | |
+ throw FileNotGoodException(itos(dbr).c_str()); | |
+ | |
+ //std::cout << "SQL prepared statements seems OK" << std::endl; | |
+ return; | |
+} | |
+ | |
+struct ActionRow | |
+{ | |
+ int id; | |
+ std::string actor; | |
+ int timestamp; | |
+ int type; | |
+ std::string location, list; | |
+ int index, add; | |
+ std::string stack; | |
+ int nodeMeta; | |
+ int x, y, z; | |
+ std::string oldNode; | |
+ int oldParam1, oldParam2; | |
+ std::string oldMeta; | |
+ std::string newNode; | |
+ int newParam1, newParam2; | |
+ std::string newMeta; | |
+ int guessed; | |
+}; | |
+ | |
+bool SQL_registerRow (ActionRow row) | |
+{ | |
+ SQL_databaseCheck(); | |
+ | |
+ sqlite3_stmt * dbs_do = (row.id)? dbs_replace: dbs_insert; | |
+ | |
+ /* | |
+ std::cout | |
+ << (row.id? "Replacing": "Inserting") | |
+ << " ActionRow" << std::endl; | |
+ */ | |
+ sqlite3_reset(dbs_do); | |
+ | |
+ int bind [20 + (((bool) row.id)? 1: 0)], ii = 0; | |
+ bool nodeMeta = false; | |
+ | |
+ bind[ii++] = sqlite3_bind_text (dbs_do, 1, row.actor.c_str(), row.actor.size(), NULL); | |
+ bind[ii++] = sqlite3_bind_int (dbs_do, 2, row.timestamp); | |
+ bind[ii++] = sqlite3_bind_int (dbs_do, 3, row.type); | |
+ | |
+ if (row.type == RollbackAction::TYPE_MODIFY_INVENTORY_STACK) | |
+ { | |
+ std::string loc = row.location; | |
+ std::string locType = loc.substr(0, loc.find(":")); | |
+ nodeMeta = (locType == "nodemeta"); | |
+ | |
+ bind[ii++] = sqlite3_bind_text (dbs_do, 4, row.list.c_str(), row.list.size(), NULL); | |
+ bind[ii++] = sqlite3_bind_int (dbs_do, 5, row.index); | |
+ bind[ii++] = sqlite3_bind_int (dbs_do, 6, row.add); | |
+ bind[ii++] = sqlite3_bind_text (dbs_do, 7, row.stack.c_str(), row.stack.size(), NULL); | |
+ bind[ii++] = sqlite3_bind_int (dbs_do, 8, (int) nodeMeta); | |
+ | |
+ if (nodeMeta) | |
+ { | |
+ std::string x, y, z; | |
+ int l, r; | |
+ l = loc.find(':') + 1; | |
+ r = loc.find(','); | |
+ x = loc.substr(l, r - l); | |
+ l = r + 1; | |
+ r = loc.find(',', l); | |
+ y = loc.substr(l, r - l); | |
+ z = loc.substr(r +1); | |
+ bind[ii++] = sqlite3_bind_int (dbs_do, 9, atoi(x.c_str())); | |
+ bind[ii++] = sqlite3_bind_int (dbs_do, 10, atoi(y.c_str())); | |
+ bind[ii++] = sqlite3_bind_int (dbs_do, 11, atoi(z.c_str())); | |
+ } | |
+ } | |
+ else | |
+ { | |
+ bind[ii++] = sqlite3_bind_null (dbs_do, 4); | |
+ bind[ii++] = sqlite3_bind_null (dbs_do, 5); | |
+ bind[ii++] = sqlite3_bind_null (dbs_do, 6); | |
+ bind[ii++] = sqlite3_bind_null (dbs_do, 7); | |
+ bind[ii++] = sqlite3_bind_null (dbs_do, 8); | |
+ } | |
+ | |
+ if (row.type == RollbackAction::TYPE_SET_NODE) | |
+ { | |
+ bind[ii++] = sqlite3_bind_int (dbs_do, 9, row.x); | |
+ bind[ii++] = sqlite3_bind_int (dbs_do, 10, row.y); | |
+ bind[ii++] = sqlite3_bind_int (dbs_do, 11, row.z); | |
+ bind[ii++] = sqlite3_bind_text (dbs_do, 12, row.oldNode.c_str(), row.oldNode.size(), NULL); | |
+ bind[ii++] = sqlite3_bind_int (dbs_do, 13, row.oldParam1); | |
+ bind[ii++] = sqlite3_bind_int (dbs_do, 14, row.oldParam2); | |
+ bind[ii++] = sqlite3_bind_text (dbs_do, 15, row.oldMeta.c_str(), row.oldMeta.size(), NULL); | |
+ bind[ii++] = sqlite3_bind_text (dbs_do, 16, row.newNode.c_str(), row.newNode.size(), NULL); | |
+ bind[ii++] = sqlite3_bind_int (dbs_do, 17, row.newParam1); | |
+ bind[ii++] = sqlite3_bind_int (dbs_do, 18, row.newParam2); | |
+ bind[ii++] = sqlite3_bind_text (dbs_do, 19, row.newMeta.c_str(), row.newMeta.size(), NULL); | |
+ bind[ii++] = sqlite3_bind_int (dbs_do, 20, row.guessed? 1: 0); | |
+ } | |
+ else | |
+ { | |
+ if (!nodeMeta) | |
+ { | |
+ bind[ii++] = sqlite3_bind_null (dbs_do, 9); | |
+ bind[ii++] = sqlite3_bind_null (dbs_do, 10); | |
+ bind[ii++] = sqlite3_bind_null (dbs_do, 11); | |
+ } | |
+ bind[ii++] = sqlite3_bind_null (dbs_do, 12); | |
+ bind[ii++] = sqlite3_bind_null (dbs_do, 13); | |
+ bind[ii++] = sqlite3_bind_null (dbs_do, 14); | |
+ bind[ii++] = sqlite3_bind_null (dbs_do, 15); | |
+ bind[ii++] = sqlite3_bind_null (dbs_do, 16); | |
+ bind[ii++] = sqlite3_bind_null (dbs_do, 17); | |
+ bind[ii++] = sqlite3_bind_null (dbs_do, 18); | |
+ bind[ii++] = sqlite3_bind_null (dbs_do, 19); | |
+ bind[ii++] = sqlite3_bind_null (dbs_do, 20); | |
+ } | |
+ | |
+ if (row.id) | |
+ bind[ii++] = sqlite3_bind_int (dbs_do, 21, row.id); | |
+ | |
+ for (ii = 0; ii < 20; ++ii) | |
+ if (bind[ii] != SQLITE_OK) | |
+ std::cout | |
+ << "WARNING: failed to bind param " << ii + 1 | |
+ << " when inserting an entry in table setnode" << std::endl; | |
+ | |
+ /* | |
+ std::cout << "========DB-WRITTEN==========" << std::endl; | |
+ std::cout << "id: " << row.id << std::endl; | |
+ std::cout << "actor: " << row.actor << std::endl; | |
+ std::cout << "time: " << row.timestamp << std::endl; | |
+ std::cout << "type: " << row.type << std::endl; | |
+ if (row.type == RollbackAction::TYPE_MODIFY_INVENTORY_STACK) | |
+ { | |
+ std::cout << "Location: " << row.location << std::endl; | |
+ std::cout << "List: " << row.list << std::endl; | |
+ std::cout << "Index: " << row.index << std::endl; | |
+ std::cout << "Add: " << row.add << std::endl; | |
+ std::cout << "Stack: " << row.stack << std::endl; | |
+ } | |
+ if (row.type == RollbackAction::TYPE_SET_NODE) | |
+ { | |
+ std::cout << "x: " << row.x << std::endl; | |
+ std::cout << "y: " << row.y << std::endl; | |
+ std::cout << "z: " << row.z << std::endl; | |
+ std::cout << "oldNode: " << row.oldNode << std::endl; | |
+ std::cout << "oldParam1: " << row.oldParam1 << std::endl; | |
+ std::cout << "oldParam2: " << row.oldParam2 << std::endl; | |
+ std::cout << "oldMeta: " << row.oldMeta << std::endl; | |
+ std::cout << "newNode: " << row.newNode << std::endl; | |
+ std::cout << "newParam1: " << row.newParam1 << std::endl; | |
+ std::cout << "newParam2: " << row.newParam2 << std::endl; | |
+ std::cout << "newMeta: " << row.newMeta << std::endl; | |
+ std::cout << "DESERIALIZE" << row.newMeta.c_str() << std::endl; | |
+ std::cout << "guessed: " << row.guessed << std::endl; | |
+ } | |
+ */ | |
+ | |
+ int written = sqlite3_step(dbs_do); | |
+ | |
+ return written == SQLITE_DONE; | |
+ | |
+ //if (written != SQLITE_DONE) | |
+ // std::cout << "WARNING: rollback action not written: " << sqlite3_errmsg(dbh) << std::endl; | |
+ //else std::cout << "Action correctly inserted via SQL" << std::endl; | |
+} | |
+ | |
+std::list<ActionRow> SQL_getRowsSince (int firstTime, std::string actor = NULL) | |
+{ | |
+ std::list<ActionRow> rows; | |
+ | |
+ sqlite3_reset (dbs_select); | |
+ sqlite3_bind_text (dbs_select, 1, actor.c_str(), -1, NULL); | |
+ sqlite3_bind_int (dbs_select, 2, firstTime); | |
+ | |
+ int select = sqlite3_step(dbs_select); | |
+ const unsigned char * text; | |
+ size_t size; | |
+ | |
+ while (select == SQLITE_ROW) | |
+ { | |
+ ActionRow row; | |
+ | |
+ text = sqlite3_column_text (dbs_select, 0); | |
+ size = sqlite3_column_bytes (dbs_select, 0); | |
+ row.actor = std::string(reinterpret_cast<const char*>(text), size); | |
+ row.timestamp = sqlite3_column_int (dbs_select, 1); | |
+ row.type = sqlite3_column_int (dbs_select, 2); | |
+ | |
+ if (row.type == RollbackAction::TYPE_MODIFY_INVENTORY_STACK) | |
+ { | |
+ text = sqlite3_column_text (dbs_select, 3); | |
+ size = sqlite3_column_bytes(dbs_select, 3); | |
+ row.list = std::string(reinterpret_cast<const char*>(text), size); | |
+ row.index = sqlite3_column_int (dbs_select, 4); | |
+ row.add = sqlite3_column_int (dbs_select, 5); | |
+ text = sqlite3_column_text (dbs_select, 6); | |
+ size = sqlite3_column_bytes(dbs_select, 6); | |
+ row.stack = std::string(reinterpret_cast<const char*>(text), size); | |
+ row.nodeMeta = sqlite3_column_int (dbs_select, 7); | |
+ } | |
+ | |
+ if (row.type == RollbackAction::TYPE_SET_NODE || row.nodeMeta) | |
+ { | |
+ row.x = sqlite3_column_int (dbs_select, 8); | |
+ row.y = sqlite3_column_int (dbs_select, 9); | |
+ row.z = sqlite3_column_int (dbs_select, 10); | |
+ } | |
+ | |
+ if (row.type == RollbackAction::TYPE_SET_NODE) | |
+ { | |
+ text = sqlite3_column_text (dbs_select, 11); | |
+ size = sqlite3_column_bytes(dbs_select, 11); | |
+ row.oldNode = std::string(reinterpret_cast<const char*>(text), size); | |
+ row.oldParam1 = sqlite3_column_int (dbs_select, 12); | |
+ row.oldParam2 = sqlite3_column_int (dbs_select, 13); | |
+ text = sqlite3_column_text (dbs_select, 14); | |
+ size = sqlite3_column_bytes(dbs_select, 14); | |
+ row.oldMeta = std::string(reinterpret_cast<const char*>(text), size); | |
+ text = sqlite3_column_text (dbs_select, 15); | |
+ size = sqlite3_column_bytes(dbs_select, 15); | |
+ row.newNode = std::string(reinterpret_cast<const char*>(text), size); | |
+ row.newParam1 = sqlite3_column_int (dbs_select, 16); | |
+ row.newParam2 = sqlite3_column_int (dbs_select, 17); | |
+ text = sqlite3_column_text (dbs_select, 18); | |
+ size = sqlite3_column_bytes(dbs_select, 18); | |
+ row.newMeta = std::string(reinterpret_cast<const char*>(text), size); | |
+ row.guessed = sqlite3_column_int (dbs_select, 19); | |
+ } | |
+ | |
+ row.location = row.nodeMeta? "nodemeta:": row.actor; | |
+ | |
+ if (row.nodeMeta) | |
+ { | |
+ row.location.append(itos(row.x)); | |
+ row.location.append(","); | |
+ row.location.append(itos(row.y)); | |
+ row.location.append(","); | |
+ row.location.append(itos(row.z)); | |
+ } | |
+ | |
+ /* | |
+ std::cout << "=======SELECTED==========\n"; | |
+ std::cout << "Actor: " << row.actor << "\n"; | |
+ std::cout << "Timestamp: " << row.timestamp << "\n"; | |
+ | |
+ if (row.type == RollbackAction::TYPE_MODIFY_INVENTORY_STACK) | |
+ { | |
+ std::cout << "list: " << row.list << "\n"; | |
+ std::cout << "index: " << row.index << "\n"; | |
+ std::cout << "add: " << row.add << "\n"; | |
+ std::cout << "stack: " << row.stack << "\n"; | |
+ if (row.nodeMeta) | |
+ { | |
+ std::cout << "X: " << row.x << "\n"; | |
+ std::cout << "Y: " << row.y << "\n"; | |
+ std::cout << "Z: " << row.z << "\n"; | |
+ } | |
+ std::cout << "Location: " << row.location << "\n"; | |
+ } | |
+ else | |
+ { | |
+ std::cout << "X: " << row.x << "\n"; | |
+ std::cout << "Y: " << row.y << "\n"; | |
+ std::cout << "Z: " << row.z << "\n"; | |
+ std::cout << "oldNode: " << row.oldNode << "\n"; | |
+ std::cout << "oldParam1: " << row.oldParam1 << "\n"; | |
+ std::cout << "oldParam2: " << row.oldParam2 << "\n"; | |
+ std::cout << "oldMeta: " << row.oldMeta << "\n"; | |
+ std::cout << "newNode: " << row.newNode << "\n"; | |
+ std::cout << "newParam1: " << row.newParam1 << "\n"; | |
+ std::cout << "newParam2: " << row.newParam2 << "\n"; | |
+ std::cout << "newMeta: " << row.newMeta << "\n"; | |
+ std::cout << "guessed: " << row.guessed << "\n"; | |
+ } | |
+ */ | |
+ | |
+ rows.push_back(row); | |
+ select = sqlite3_step(dbs_select); | |
+ } | |
+ | |
+ return rows; | |
+} | |
+std::list<RollbackAction> SQL_getActionsSince (int firstTime, std::string actor = NULL) | |
+{ | |
+ std::list<RollbackAction> actions; | |
+ std::list<ActionRow> rows = SQL_getRowsSince(firstTime, actor); | |
+ | |
+ std::list<ActionRow>::const_iterator it; | |
+ for (it = rows.begin(); it != rows.end(); ++it) | |
+ { | |
+ RollbackAction action; | |
+ action.actor = it->actor; | |
+ action.unix_time = it->timestamp; | |
+ action.type = static_cast<RollbackAction::Type>(it->type); | |
+ | |
+ switch (action.type) | |
+ { | |
+ case RollbackAction::TYPE_MODIFY_INVENTORY_STACK: | |
+ | |
+ action.inventory_location = it->location.c_str(); | |
+ action.inventory_list = it->list; | |
+ action.inventory_index = it->index; | |
+ action.inventory_add = it->add; | |
+ action.inventory_stack = it->stack; | |
+ break; | |
+ | |
+ case RollbackAction::TYPE_SET_NODE: | |
+ | |
+ action.p = v3s16(it->x, it->y, it->z); | |
+ action.n_old.name = it->oldNode; | |
+ action.n_old.param1 = it->oldParam1; | |
+ action.n_old.param2 = it->oldParam2; | |
+ action.n_old.meta = it->oldMeta; | |
+ action.n_new.name = it->newNode; | |
+ action.n_new.param1 = it->newParam1; | |
+ action.n_new.param2 = it->newParam2; | |
+ action.n_new.meta = it->newMeta; | |
+ break; | |
+ | |
+ default: | |
+ | |
+ throw("W T F"); | |
+ break; | |
+ } | |
+ | |
+ actions.push_back(action); | |
+ } | |
+ return actions; | |
+} | |
+ | |
// Get nearness factor for subject's action for this action | |
// Return value: 0 = impossible, >0 = factor | |
static float getSuspectNearness(bool is_guess, v3s16 suspect_p, int suspect_t, | |
@@ -65,29 +533,36 @@ class RollbackManager: public IRollbackManager | |
void reportAction(const RollbackAction &action_) | |
{ | |
// Ignore if not important | |
- if(!action_.isImportant(m_gamedef)) | |
+ if (!action_.isImportant(m_gamedef)) | |
return; | |
+ | |
RollbackAction action = action_; | |
action.unix_time = time(0); | |
+ | |
// Figure out actor | |
action.actor = m_current_actor; | |
action.actor_is_guess = m_current_actor_is_guess; | |
- // If actor is not known, find out suspect or cancel | |
- if(action.actor.empty()){ | |
+ | |
+ if (action.actor.empty()) // If actor is not known, find out suspect or cancel | |
+ { | |
v3s16 p; | |
- if(!action.getPosition(&p)) | |
+ if (!action.getPosition(&p)) | |
return; | |
+ | |
action.actor = getSuspect(p, 83, 1); | |
- if(action.actor.empty()) | |
+ if (action.actor.empty()) | |
return; | |
+ | |
action.actor_is_guess = true; | |
} | |
- infostream<<"RollbackManager::reportAction():" | |
- <<" time="<<action.unix_time | |
- <<" actor=\""<<action.actor<<"\"" | |
- <<(action.actor_is_guess?" (guess)":"") | |
- <<" action="<<action.toString() | |
- <<std::endl; | |
+ | |
+ infostream | |
+ << "RollbackManager::reportAction():" | |
+ << " time="<<action.unix_time | |
+ << " actor=\""<<action.actor<<"\"" | |
+ << (action.actor_is_guess?" (guess)":"") | |
+ << " action="<<action.toString() | |
+ << std::endl; | |
addAction(action); | |
} | |
std::string getActor() | |
@@ -140,43 +615,253 @@ class RollbackManager: public IRollbackManager | |
} | |
void flush() | |
{ | |
+ | |
infostream<<"RollbackManager::flush()"<<std::endl; | |
+ | |
+ /* | |
std::ofstream of(m_filepath.c_str(), std::ios::app); | |
if(!of.good()){ | |
errorstream<<"RollbackManager::flush(): Could not open file " | |
<<"for appending: \""<<m_filepath<<"\""<<std::endl; | |
return; | |
} | |
- for(std::list<RollbackAction>::const_iterator | |
- i = m_action_todisk_buffer.begin(); | |
- i != m_action_todisk_buffer.end(); i++) | |
+ */ | |
+ | |
+ sqlite3_exec(dbh, "BEGIN", NULL, NULL, NULL); | |
+ | |
+ for | |
+ ( std::list<RollbackAction>::const_iterator i = m_action_todisk_buffer.begin() | |
+ ; i != m_action_todisk_buffer.end() | |
+ ; i++) | |
{ | |
- // Do not save stuff that does not have an actor | |
- if(i->actor == "") | |
- continue; | |
- of<<i->unix_time; | |
- of<<" "; | |
- of<<serializeJsonString(i->actor); | |
- of<<" "; | |
- of<<i->toString(); | |
- if(i->actor_is_guess){ | |
- of<<" "; | |
- of<<"actor_is_guess"; | |
+ if (i->actor == "") continue; // Do not save stuff that does not have an actor | |
+ | |
+ /* | |
+ of << i->unix_time; | |
+ of << " "; | |
+ of << serializeJsonString(i->actor); | |
+ of << " "; | |
+ of << i->toString(); | |
+ if (i->actor_is_guess) | |
+ { | |
+ of << " "; | |
+ of << "actor_is_guess"; | |
} | |
- of<<std::endl; | |
+ of << std::endl; | |
+ */ | |
+ | |
+ ActionRow row; | |
+ | |
+ row.id = 0; | |
+ row.actor = i->actor; | |
+ row.timestamp = i->unix_time; | |
+ row.type = i->type; | |
+ | |
+ if (row.type == RollbackAction::TYPE_MODIFY_INVENTORY_STACK) | |
+ { | |
+ row.location = i->inventory_location; | |
+ row.list = i->inventory_list; | |
+ row.index = i->inventory_index; | |
+ row.add = i->inventory_add; | |
+ row.stack = i->inventory_stack; | |
+ } | |
+ else | |
+ { | |
+ row.x = i->p.X; | |
+ row.y = i->p.Y; | |
+ row.z = i->p.Z; | |
+ row.oldNode = i->n_old.name; | |
+ row.oldParam1 = i->n_old.param1; | |
+ row.oldParam2 = i->n_old.param2; | |
+ row.oldMeta = i->n_old.meta; | |
+ row.newNode = i->n_new.name; | |
+ row.newParam1 = i->n_new.param1; | |
+ row.newParam2 = i->n_new.param2; | |
+ row.newMeta = i->n_new.meta; | |
+ row.guessed = i->actor_is_guess; | |
+ } | |
+ SQL_registerRow(row); | |
+ | |
} | |
+ sqlite3_exec(dbh, "COMMIT", NULL, NULL, NULL); | |
m_action_todisk_buffer.clear(); | |
} | |
// Other | |
+ void TXT_fileCheck (std::string filepath) | |
+ { | |
+ if (!fs::PathExists(filepath)) return; | |
+ | |
+ std::cout << "Migrating from rollback.txt to rollback.sqlite" << std::endl; | |
+ | |
+ SQL_databaseCheck(); | |
+ | |
+ std::ifstream fh (m_filepath.c_str(), std::ios::in | std::ios::ate); | |
+ if (!fh.good()) throw("DIE"); | |
+ | |
+ int filesize = fh.tellg(); | |
+ | |
+ if (filesize > 10) | |
+ { | |
+ fh.seekg(0); | |
+ | |
+ using namespace std; | |
+ | |
+ std::string bit; | |
+ int i = 0; | |
+ int id = 1; | |
+ int t = 0; | |
+ do | |
+ { | |
+ ActionRow row; | |
+ | |
+ row.id = id; | |
+ | |
+ // Get the timestamp | |
+ std::getline(fh, bit, ' '); bit = trim(bit); if (!atoi(trim(bit).c_str())) { std::getline(fh, bit); continue; } | |
+ row.timestamp = atoi(bit.c_str()); | |
+ | |
+ // Get the actor | |
+ row.actor = trim(deSerializeJsonString(fh)); | |
+ | |
+ // Get the action type | |
+ std::getline(fh, bit, '['); | |
+ std::getline(fh, bit, ' '); | |
+ | |
+ if (bit == "modify_inventory_stack") | |
+ row.type = RollbackAction::TYPE_MODIFY_INVENTORY_STACK; | |
+ | |
+ if (bit == "set_node") | |
+ row.type = RollbackAction::TYPE_SET_NODE; | |
+ | |
+ if (row.type == RollbackAction::TYPE_MODIFY_INVENTORY_STACK) | |
+ { | |
+ row.location = trim(deSerializeJsonString(fh)); | |
+ std::getline(fh, bit, ' '); row.list = trim(deSerializeJsonString(fh)); | |
+ std::getline(fh, bit, ' '); | |
+ std::getline(fh, bit, ' '); | |
+ row.index = atoi(trim(bit).c_str()); | |
+ std::getline(fh, bit, ' '); row.add = (int) ( trim(bit) == "add" ); | |
+ row.stack = trim(deSerializeJsonString(fh)); | |
+ std::getline(fh, bit); | |
+ | |
+ } | |
+ else | |
+ if (row.type == RollbackAction::TYPE_SET_NODE) | |
+ { | |
+ std::getline(fh, bit, '('); | |
+ std::getline(fh, bit, ','); row.x = atoi(trim(bit).c_str()); | |
+ std::getline(fh, bit, ','); row.y = atoi(trim(bit).c_str()); | |
+ std::getline(fh, bit, ')'); row.z = atoi(trim(bit).c_str()); | |
+ std::getline(fh, bit, ' '); row.oldNode = trim(deSerializeJsonString(fh)); | |
+ std::getline(fh, bit, ' '); | |
+ std::getline(fh, bit, ' '); row.oldParam1 = atoi(trim(bit).c_str()); | |
+ std::getline(fh, bit, ' '); row.oldParam2 = atoi(trim(bit).c_str()); | |
+ row.oldMeta = trim(deSerializeJsonString(fh)); | |
+ std::getline(fh, bit, ' '); row.newNode = trim(deSerializeJsonString(fh)); | |
+ std::getline(fh, bit, ' '); | |
+ std::getline(fh, bit, ' '); row.newParam1 = atoi(trim(bit).c_str()); | |
+ std::getline(fh, bit, ' '); row.newParam2 = atoi(trim(bit).c_str()); | |
+ row.newMeta = trim(deSerializeJsonString(fh)); | |
+ std::getline(fh, bit, ' '); | |
+ std::getline(fh, bit, ' '); | |
+ std::getline(fh, bit); row.guessed = (int) ( trim(bit) == "actor_is_guess" ); | |
+ } | |
+ | |
+ /* | |
+ std::cout << "==========READ===========" << std::endl; | |
+ std::cout << "time: " << row.timestamp << std::endl; | |
+ std::cout << "actor: " << row.actor << std::endl; | |
+ std::cout << "type: " << row.type << std::endl; | |
+ if (row.type == RollbackAction::TYPE_MODIFY_INVENTORY_STACK) | |
+ { | |
+ std::cout << "Location: " << row.location << std::endl; | |
+ std::cout << "List: " << row.list << std::endl; | |
+ std::cout << "Index: " << row.index << std::endl; | |
+ std::cout << "Add: " << row.add << std::endl; | |
+ std::cout << "Stack: " << row.stack << std::endl; | |
+ } | |
+ if (row.type == RollbackAction::TYPE_SET_NODE) | |
+ { | |
+ std::cout << "x: " << row.x << std::endl; | |
+ std::cout << "y: " << row.y << std::endl; | |
+ std::cout << "z: " << row.z << std::endl; | |
+ std::cout << "oldNode: " << row.oldNode << std::endl; | |
+ std::cout << "oldParam1: " << row.oldParam1 << std::endl; | |
+ std::cout << "oldParam2: " << row.oldParam2 << std::endl; | |
+ std::cout << "oldMeta: " << row.oldMeta << std::endl; | |
+ std::cout << "newNode: " << row.newNode << std::endl; | |
+ std::cout << "newParam1: " << row.newParam1 << std::endl; | |
+ std::cout << "newParam2: " << row.newParam2 << std::endl; | |
+ std::cout << "newMeta: " << row.newMeta << std::endl; | |
+ std::cout << "guessed: " << row.guessed << std::endl; | |
+ } | |
+ */ | |
+ | |
+ if (i == 0) | |
+ { | |
+ t = time(0); | |
+ sqlite3_exec(dbh, "BEGIN", NULL, NULL, NULL); | |
+ } | |
+ | |
+ SQL_registerRow(row); | |
+ | |
+ if (++i == 10000) | |
+ { | |
+ sqlite3_exec(dbh, "COMMIT", NULL, NULL, NULL); | |
+ | |
+ t = time(0) - t; | |
+ std::cout | |
+ << " Done: " << (int)(((float) fh.tellg() / (float) filesize) * 100) << "%" | |
+ << "\tSpeed: " << 10000 / (t == 0? 1: t) << " actions per second" | |
+ << "\r" | |
+ ; | |
+ std::cout.flush(); | |
+ i = 0; | |
+ } | |
+ | |
+ ++id; | |
+ } | |
+ while (!fh.eof() && fh.good()); | |
+ } | |
+ | |
+ std::cout | |
+ << " Done: 100%" << std::endl | |
+ << " Deleting old rollback.txt..."; | |
+ | |
+ bool deleted = fs::DeleteSingleFileOrEmptyDirectory(filepath); | |
+ | |
+ std::cout << (deleted? "OK": "FAIL") << std::endl; | |
+ | |
+ if (!deleted) | |
+ std::cout << "Could not delete the old rollback.txt file, you will need to delete it manually." << std::endl; | |
+} | |
+ | |
RollbackManager(const std::string &filepath, IGameDef *gamedef): | |
m_filepath(filepath), | |
m_gamedef(gamedef), | |
m_current_actor_is_guess(false) | |
{ | |
- infostream<<"RollbackManager::RollbackManager("<<filepath<<")" | |
- <<std::endl; | |
+ infostream | |
+ << "RollbackManager::RollbackManager(" << filepath << ")" | |
+ << std::endl; | |
+ | |
+ // Operate correctly in case of still being given rollback.txt as filepath | |
+ std::string directory = filepath.substr(0, filepath.rfind(DIR_DELIM) + 1); //std::cout << "Directory: " << directory << std::endl; | |
+ std::string filenameOld = filepath.substr(1+ filepath.rfind(DIR_DELIM)); //std::cout << "Filename: " << filenameOld << std::endl; | |
+ std::string filenameNew = (filenameOld == "rollback.txt")? "rollback.sqlite": filenameOld; | |
+ std::string checkfor = directory + "rollback.txt"; | |
+ | |
+ dbp = directory + filenameNew; | |
+ TXT_fileCheck(filepath); | |
+ | |
+ /* | |
+ m_filepath = filepath.substr(0, filepath.rfind("/rollback.txt")); | |
+ m_filepath.append("/rollback.sqlite"); | |
+ */ | |
+ | |
+ SQL_databaseCheck(); | |
} | |
~RollbackManager() | |
{ | |
@@ -190,7 +875,7 @@ class RollbackManager: public IRollbackManager | |
m_action_latest_buffer.push_back(action); | |
// Flush to disk sometimes | |
- if(m_action_todisk_buffer.size() >= 100) | |
+ if(m_action_todisk_buffer.size() >= 1000) // TEMP | |
flush(); | |
} | |
@@ -259,9 +944,12 @@ class RollbackManager: public IRollbackManager | |
{ | |
// Save all remaining stuff | |
flush(); | |
+ | |
// Load whole file to memory | |
bool good = readFile(action_buffer); | |
- if(!good){ | |
+ | |
+ if(!good) | |
+ { | |
errorstream<<"RollbackManager::getEntriesSince(): Failed to" | |
<<" open file; using data in memory."<<std::endl; | |
action_buffer = m_action_latest_buffer; | |
@@ -319,13 +1007,17 @@ class RollbackManager: public IRollbackManager | |
{ | |
infostream<<"RollbackManager::getRevertActions("<<actor_filter | |
<<", "<<seconds<<")"<<std::endl; | |
+ | |
// Figure out time | |
int cur_time = time(0); | |
int first_time = cur_time - seconds; | |
- std::list<RollbackAction> action_buffer = getEntriesSince(first_time); | |
+ flush(); | |
- std::list<RollbackAction> result; | |
+ std::list<RollbackAction> result = SQL_getActionsSince(first_time, actor_filter); | |
+ | |
+ return result; | |
+ /* | |
for(std::list<RollbackAction>::const_reverse_iterator | |
i = action_buffer.rbegin(); | |
@@ -336,15 +1028,15 @@ class RollbackManager: public IRollbackManager | |
if(i->actor != actor_filter) | |
continue; | |
const RollbackAction &action = *i; | |
- /*infostream<<"RollbackManager::revertAction(): Should revert" | |
+ infostream<<"RollbackManager::revertAction(): Should revert" | |
<<" time="<<action.unix_time | |
<<" actor=\""<<action.actor<<"\"" | |
<<" action="<<action.toString() | |
- <<std::endl;*/ | |
+ <<std::endl; | |
result.push_back(action); | |
} | |
- | |
return result; | |
+ */ | |
} | |
private: |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment