mirror of
https://github.com/luanti-org/luanti.git
synced 2025-11-06 18:25:21 +01:00
Fix memory leak in rollback (and more) (#16644)
This commit is contained in:
@@ -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),
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
Reference in New Issue
Block a user