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