1
0
mirror of https://github.com/luanti-org/luanti.git synced 2025-11-06 10:15:19 +01:00

Fix memory leak in rollback (and more) (#16644)

This commit is contained in:
sfan5
2025-11-05 11:55:57 +01:00
committed by GitHub
parent 7a6e639d61
commit 2368126d0a
4 changed files with 43 additions and 40 deletions

View File

@@ -1057,10 +1057,6 @@ anticheat_flags (Anticheat flags) flags digging,interaction,movement digging,int
# Increase the value if players experience stuttery movement. # Increase the value if players experience stuttery movement.
anticheat_movement_tolerance (Anticheat movement tolerance) float 1.0 1.0 anticheat_movement_tolerance (Anticheat movement tolerance) float 1.0 1.0
# If enabled, actions are recorded for rollback.
# This option is only read when server starts.
enable_rollback_recording (Rollback recording) bool false
[**Client-side Modding] [**Client-side Modding]
# Restricts the access of certain client-side functions on servers. # Restricts the access of certain client-side functions on servers.
@@ -2249,6 +2245,11 @@ kick_msg_crash (Crash message) string This server has experienced an internal er
# Set this to true if your server is set up to restart automatically. # Set this to true if your server is set up to restart automatically.
ask_reconnect_on_crash (Ask to reconnect after crash) bool false ask_reconnect_on_crash (Ask to reconnect after crash) bool false
# If enabled, node and inventory actions are recorded for rollback.
# This option is only read on server start. Note that the engine will not
# automatically clean old entries from the rollback database.
enable_rollback_recording (Rollback recording) bool false
[**Server/Env Performance] [server] [**Server/Env Performance] [server]
# Length of a server tick (the interval at which everything is generally updated), # Length of a server tick (the interval at which everything is generally updated),

View File

@@ -22,12 +22,15 @@ struct RollbackNode
int param2 = 0; int param2 = 0;
std::string meta; std::string meta;
bool operator == (const RollbackNode &other) bool operator == (const RollbackNode &other) const
{ {
return (name == other.name && param1 == other.param1 && return (name == other.name && param1 == other.param1 &&
param2 == other.param2 && meta == other.meta); param2 == other.param2 && meta == other.meta);
} }
bool operator != (const RollbackNode &other) { return !(*this == other); } bool operator != (const RollbackNode &other) const
{
return !(*this == other);
}
RollbackNode() = default; RollbackNode() = default;
@@ -37,15 +40,16 @@ struct RollbackNode
struct RollbackAction struct RollbackAction
{ {
enum Type{ enum Type : u8 {
TYPE_NOTHING, TYPE_NOTHING,
TYPE_SET_NODE, TYPE_SET_NODE,
TYPE_MODIFY_INVENTORY_STACK, TYPE_MODIFY_INVENTORY_STACK,
} type = TYPE_NOTHING; };
time_t unix_time = 0; time_t unix_time = 0;
std::string actor; std::string actor;
bool actor_is_guess = false; bool actor_is_guess = false;
Type type = TYPE_NOTHING;
v3s16 p; v3s16 p;
RollbackNode n_old; RollbackNode n_old;

View File

@@ -17,7 +17,7 @@
#include "sqlite3.h" #include "sqlite3.h"
#include "filesys.h" #include "filesys.h"
#define POINTS_PER_NODE (16.0) #define POINTS_PER_NODE (16.0f)
#define SQLRES(f, good) \ #define SQLRES(f, good) \
if ((f) != (good)) {\ if ((f) != (good)) {\
@@ -44,11 +44,11 @@ public:
return *this; return *this;
} }
int id; int id = 0;
}; };
struct ActionRow { struct ActionRow {
int id; int id = 0;
int actor; int actor;
time_t timestamp; time_t timestamp;
int type; int type;
@@ -231,7 +231,6 @@ bool RollbackManager::createTables()
"CREATE INDEX IF NOT EXISTS `actionIndex` ON `action`(`x`,`y`,`z`,`timestamp`,`actor`);\n" "CREATE INDEX IF NOT EXISTS `actionIndex` ON `action`(`x`,`y`,`z`,`timestamp`,`actor`);\n"
"CREATE INDEX IF NOT EXISTS `actionTimestampActorIndex` ON `action`(`timestamp`,`actor`);\n", "CREATE INDEX IF NOT EXISTS `actionTimestampActorIndex` ON `action`(`timestamp`,`actor`);\n",
NULL, NULL, NULL)); NULL, NULL, NULL));
verbosestream << "SQL Rollback: SQLite3 database structure was created" << std::endl;
return true; return true;
} }
@@ -241,13 +240,10 @@ bool RollbackManager::initDatabase()
{ {
verbosestream << "RollbackManager: Database connection setup" << std::endl; verbosestream << "RollbackManager: Database connection setup" << std::endl;
bool needs_create = !fs::PathExists(database_path);
SQLOK(sqlite3_open_v2(database_path.c_str(), &db, SQLOK(sqlite3_open_v2(database_path.c_str(), &db,
SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL)); SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL));
if (needs_create) { createTables();
createTables();
}
SQLOK(sqlite3_prepare_v2(db, SQLOK(sqlite3_prepare_v2(db,
"INSERT INTO `action` (\n" "INSERT INTO `action` (\n"
@@ -362,7 +358,7 @@ bool RollbackManager::initDatabase()
} }
SQLOK(sqlite3_reset(stmt_knownNode_select)); SQLOK(sqlite3_reset(stmt_knownNode_select));
return needs_create; return true;
} }
@@ -522,7 +518,6 @@ ActionRow RollbackManager::actionRowFromRollbackAction(const RollbackAction & ac
{ {
ActionRow row; ActionRow row;
row.id = 0;
row.actor = getActorId(action.actor); row.actor = getActorId(action.actor);
row.timestamp = action.unix_time; row.timestamp = action.unix_time;
row.type = action.type; row.type = action.type;
@@ -589,7 +584,7 @@ const std::list<RollbackAction> RollbackManager::rollbackActionsFromActionRows(
break; break;
default: default:
throw ("W.T.F."); assert(false);
break; break;
} }
@@ -667,12 +662,10 @@ float RollbackManager::getSuspectNearness(bool is_guess, v3s16 suspect_p,
f -= 1 * (action_t - suspect_t); f -= 1 * (action_t - suspect_t);
// If is a guess, halve the points // If is a guess, halve the points
if (is_guess) { if (is_guess) {
f *= 0.5; f /= 2;
} }
// Limit to 0 // Limit to 0
if (f < 0) { f = MYMAX(f, 0);
f = 0;
}
return f; return f;
} }
@@ -730,12 +723,11 @@ std::string RollbackManager::getSuspect(v3s16 p, float nearness_shortcut,
if (!current_actor.empty()) { if (!current_actor.empty()) {
return current_actor; return current_actor;
} }
int cur_time = time(0); time_t cur_time = time(0);
time_t first_time = cur_time - (100 - min_nearness); time_t first_time = cur_time - (100 - min_nearness);
RollbackAction likely_suspect; RollbackAction likely_suspect;
float likely_suspect_nearness = 0; float likely_suspect_nearness = 0;
for (std::list<RollbackAction>::const_reverse_iterator for (auto i = action_latest_buffer.rbegin();
i = action_latest_buffer.rbegin();
i != action_latest_buffer.rend(); ++i) { i != action_latest_buffer.rend(); ++i) {
if (i->unix_time < first_time) { if (i->unix_time < first_time) {
break; break;
@@ -795,15 +787,20 @@ void RollbackManager::addAction(const RollbackAction & action)
if (action_todisk_buffer.size() >= 500) { if (action_todisk_buffer.size() >= 500) {
flush(); flush();
} }
// Cut off latest log sometimes
while (action_latest_buffer.size() >= 500) {
action_latest_buffer.pop_front();
}
} }
std::list<RollbackAction> RollbackManager::getNodeActors(v3s16 pos, int range, std::list<RollbackAction> RollbackManager::getNodeActors(v3s16 pos, int range,
time_t seconds, int limit) time_t seconds, int limit)
{ {
flush();
time_t cur_time = time(0); time_t cur_time = time(0);
time_t first_time = cur_time - seconds; time_t first_time = cur_time - seconds;
flush();
return getActionsSince_range(first_time, pos, range, limit); return getActionsSince_range(first_time, pos, range, limit);
} }

View File

@@ -9,6 +9,7 @@
#include "rollback_interface.h" #include "rollback_interface.h"
#include <list> #include <list>
#include <vector> #include <vector>
#include <deque>
#include "sqlite3.h" #include "sqlite3.h"
class IGameDef; class IGameDef;
@@ -16,7 +17,7 @@ class IGameDef;
struct ActionRow; struct ActionRow;
struct Entity; struct Entity;
class RollbackManager: public IRollbackManager class RollbackManager final : public IRollbackManager
{ {
public: public:
RollbackManager(const std::string & world_path, IGameDef * gamedef); RollbackManager(const std::string & world_path, IGameDef * gamedef);
@@ -67,20 +68,20 @@ private:
std::string current_actor; std::string current_actor;
bool current_actor_is_guess = false; bool current_actor_is_guess = false;
std::list<RollbackAction> action_todisk_buffer; std::vector<RollbackAction> action_todisk_buffer;
std::list<RollbackAction> action_latest_buffer; std::deque<RollbackAction> action_latest_buffer;
std::string database_path; std::string database_path;
sqlite3 * db; sqlite3 *db = nullptr;
sqlite3_stmt * stmt_insert; sqlite3_stmt *stmt_insert = nullptr;
sqlite3_stmt * stmt_replace; sqlite3_stmt *stmt_replace = nullptr;
sqlite3_stmt * stmt_select; sqlite3_stmt *stmt_select = nullptr;
sqlite3_stmt * stmt_select_range; sqlite3_stmt *stmt_select_range = nullptr;
sqlite3_stmt * stmt_select_withActor; sqlite3_stmt *stmt_select_withActor = nullptr;
sqlite3_stmt * stmt_knownActor_select; sqlite3_stmt *stmt_knownActor_select = nullptr;
sqlite3_stmt * stmt_knownActor_insert; sqlite3_stmt *stmt_knownActor_insert = nullptr;
sqlite3_stmt * stmt_knownNode_select; sqlite3_stmt *stmt_knownNode_select = nullptr;
sqlite3_stmt * stmt_knownNode_insert; sqlite3_stmt *stmt_knownNode_insert = nullptr;
std::vector<Entity> knownActors; std::vector<Entity> knownActors;
std::vector<Entity> knownNodes; std::vector<Entity> knownNodes;