Verify database connection on interval (#9665)

This commit is contained in:
Loïc Blot 2020-04-15 08:01:11 +02:00 committed by GitHub
parent 62c62f3829
commit 5c588f89e7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 65 additions and 33 deletions

@ -90,13 +90,19 @@ void Database_PostgreSQL::connectToDatabase()
initStatements(); initStatements();
} }
void Database_PostgreSQL::verifyDatabase() void Database_PostgreSQL::pingDatabase()
{ {
if (PQstatus(m_conn) == CONNECTION_OK) // Verify DB connection with ping
return; try {
PQreset(m_conn);
ping(); ping();
} catch (const DatabaseException &e) {
// If ping failed, show the error and try reconnect
PQreset(m_conn);
errorstream << e.what() << std::endl
<< "Reconnecting to database " << m_connect_string << std::endl;
connectToDatabase();
}
} }
void Database_PostgreSQL::ping() void Database_PostgreSQL::ping()
@ -151,7 +157,7 @@ void Database_PostgreSQL::createTableIfNotExists(const std::string &table_name,
void Database_PostgreSQL::beginSave() void Database_PostgreSQL::beginSave()
{ {
verifyDatabase(); pingDatabase();
checkResults(PQexec(m_conn, "BEGIN;")); checkResults(PQexec(m_conn, "BEGIN;"));
} }
@ -227,7 +233,7 @@ bool MapDatabasePostgreSQL::saveBlock(const v3s16 &pos, const std::string &data)
return false; return false;
} }
verifyDatabase(); pingDatabase();
s32 x, y, z; s32 x, y, z;
x = htonl(pos.X); x = htonl(pos.X);
@ -251,7 +257,7 @@ bool MapDatabasePostgreSQL::saveBlock(const v3s16 &pos, const std::string &data)
void MapDatabasePostgreSQL::loadBlock(const v3s16 &pos, std::string *block) void MapDatabasePostgreSQL::loadBlock(const v3s16 &pos, std::string *block)
{ {
verifyDatabase(); pingDatabase();
s32 x, y, z; s32 x, y, z;
x = htonl(pos.X); x = htonl(pos.X);
@ -275,7 +281,7 @@ void MapDatabasePostgreSQL::loadBlock(const v3s16 &pos, std::string *block)
bool MapDatabasePostgreSQL::deleteBlock(const v3s16 &pos) bool MapDatabasePostgreSQL::deleteBlock(const v3s16 &pos)
{ {
verifyDatabase(); pingDatabase();
s32 x, y, z; s32 x, y, z;
x = htonl(pos.X); x = htonl(pos.X);
@ -293,7 +299,7 @@ bool MapDatabasePostgreSQL::deleteBlock(const v3s16 &pos)
void MapDatabasePostgreSQL::listAllLoadableBlocks(std::vector<v3s16> &dst) void MapDatabasePostgreSQL::listAllLoadableBlocks(std::vector<v3s16> &dst)
{ {
verifyDatabase(); pingDatabase();
PGresult *results = execPrepared("list_all_loadable_blocks", 0, PGresult *results = execPrepared("list_all_loadable_blocks", 0,
NULL, NULL, NULL, false, false); NULL, NULL, NULL, false, false);
@ -435,7 +441,7 @@ void PlayerDatabasePostgreSQL::initStatements()
bool PlayerDatabasePostgreSQL::playerDataExists(const std::string &playername) bool PlayerDatabasePostgreSQL::playerDataExists(const std::string &playername)
{ {
verifyDatabase(); pingDatabase();
const char *values[] = { playername.c_str() }; const char *values[] = { playername.c_str() };
PGresult *results = execPrepared("load_player", 1, values, false); PGresult *results = execPrepared("load_player", 1, values, false);
@ -451,7 +457,7 @@ void PlayerDatabasePostgreSQL::savePlayer(RemotePlayer *player)
if (!sao) if (!sao)
return; return;
verifyDatabase(); pingDatabase();
v3f pos = sao->getBasePosition(); v3f pos = sao->getBasePosition();
std::string pitch = ftos(sao->getLookPitch()); std::string pitch = ftos(sao->getLookPitch());
@ -535,7 +541,7 @@ void PlayerDatabasePostgreSQL::savePlayer(RemotePlayer *player)
bool PlayerDatabasePostgreSQL::loadPlayer(RemotePlayer *player, PlayerSAO *sao) bool PlayerDatabasePostgreSQL::loadPlayer(RemotePlayer *player, PlayerSAO *sao)
{ {
sanity_check(sao); sanity_check(sao);
verifyDatabase(); pingDatabase();
const char *values[] = { player->getName() }; const char *values[] = { player->getName() };
PGresult *results = execPrepared("load_player", 1, values, false, false); PGresult *results = execPrepared("load_player", 1, values, false, false);
@ -610,7 +616,7 @@ bool PlayerDatabasePostgreSQL::removePlayer(const std::string &name)
if (!playerDataExists(name)) if (!playerDataExists(name))
return false; return false;
verifyDatabase(); pingDatabase();
const char *values[] = { name.c_str() }; const char *values[] = { name.c_str() };
execPrepared("remove_player", 1, values); execPrepared("remove_player", 1, values);
@ -620,7 +626,7 @@ bool PlayerDatabasePostgreSQL::removePlayer(const std::string &name)
void PlayerDatabasePostgreSQL::listPlayers(std::vector<std::string> &res) void PlayerDatabasePostgreSQL::listPlayers(std::vector<std::string> &res)
{ {
verifyDatabase(); pingDatabase();
PGresult *results = execPrepared("load_player_list", 0, NULL, false); PGresult *results = execPrepared("load_player_list", 0, NULL, false);

@ -32,12 +32,13 @@ public:
Database_PostgreSQL(const std::string &connect_string); Database_PostgreSQL(const std::string &connect_string);
~Database_PostgreSQL(); ~Database_PostgreSQL();
virtual void pingDatabase();
void beginSave(); void beginSave();
void endSave(); void endSave();
bool initialized() const; bool initialized() const;
protected: protected:
// Conversion helpers // Conversion helpers
inline int pg_to_int(PGresult *res, int row, int col) inline int pg_to_int(PGresult *res, int row, int col)
@ -82,7 +83,6 @@ protected:
} }
void createTableIfNotExists(const std::string &table_name, const std::string &definition); void createTableIfNotExists(const std::string &table_name, const std::string &definition);
void verifyDatabase();
// Database initialization // Database initialization
void connectToDatabase(); void connectToDatabase();
@ -113,6 +113,8 @@ public:
MapDatabasePostgreSQL(const std::string &connect_string); MapDatabasePostgreSQL(const std::string &connect_string);
virtual ~MapDatabasePostgreSQL() = default; virtual ~MapDatabasePostgreSQL() = default;
virtual void pingDatabase() { Database_PostgreSQL::pingDatabase(); }
bool saveBlock(const v3s16 &pos, const std::string &data); bool saveBlock(const v3s16 &pos, const std::string &data);
void loadBlock(const v3s16 &pos, std::string *block); void loadBlock(const v3s16 &pos, std::string *block);
bool deleteBlock(const v3s16 &pos); bool deleteBlock(const v3s16 &pos);
@ -132,6 +134,8 @@ public:
PlayerDatabasePostgreSQL(const std::string &connect_string); PlayerDatabasePostgreSQL(const std::string &connect_string);
virtual ~PlayerDatabasePostgreSQL() = default; virtual ~PlayerDatabasePostgreSQL() = default;
virtual void pingDatabase() { Database_PostgreSQL::pingDatabase(); }
void savePlayer(RemotePlayer *player); void savePlayer(RemotePlayer *player);
bool loadPlayer(RemotePlayer *player, PlayerSAO *sao); bool loadPlayer(RemotePlayer *player, PlayerSAO *sao);
bool removePlayer(const std::string &name); bool removePlayer(const std::string &name);

@ -121,7 +121,7 @@ Database_SQLite3::Database_SQLite3(const std::string &savedir, const std::string
void Database_SQLite3::beginSave() void Database_SQLite3::beginSave()
{ {
verifyDatabase(); pingDatabase();
SQLRES(sqlite3_step(m_stmt_begin), SQLITE_DONE, SQLRES(sqlite3_step(m_stmt_begin), SQLITE_DONE,
"Failed to start SQLite3 transaction"); "Failed to start SQLite3 transaction");
sqlite3_reset(m_stmt_begin); sqlite3_reset(m_stmt_begin);
@ -129,7 +129,7 @@ void Database_SQLite3::beginSave()
void Database_SQLite3::endSave() void Database_SQLite3::endSave()
{ {
verifyDatabase(); pingDatabase();
SQLRES(sqlite3_step(m_stmt_end), SQLITE_DONE, SQLRES(sqlite3_step(m_stmt_end), SQLITE_DONE,
"Failed to commit SQLite3 transaction"); "Failed to commit SQLite3 transaction");
sqlite3_reset(m_stmt_end); sqlite3_reset(m_stmt_end);
@ -171,7 +171,7 @@ void Database_SQLite3::openDatabase()
"Failed to enable sqlite3 foreign key support"); "Failed to enable sqlite3 foreign key support");
} }
void Database_SQLite3::verifyDatabase() void Database_SQLite3::pingDatabase()
{ {
if (m_initialized) return; if (m_initialized) return;
@ -247,7 +247,7 @@ inline void MapDatabaseSQLite3::bindPos(sqlite3_stmt *stmt, const v3s16 &pos, in
bool MapDatabaseSQLite3::deleteBlock(const v3s16 &pos) bool MapDatabaseSQLite3::deleteBlock(const v3s16 &pos)
{ {
verifyDatabase(); pingDatabase();
bindPos(m_stmt_delete, pos); bindPos(m_stmt_delete, pos);
@ -263,7 +263,7 @@ bool MapDatabaseSQLite3::deleteBlock(const v3s16 &pos)
bool MapDatabaseSQLite3::saveBlock(const v3s16 &pos, const std::string &data) bool MapDatabaseSQLite3::saveBlock(const v3s16 &pos, const std::string &data)
{ {
verifyDatabase(); pingDatabase();
#ifdef __ANDROID__ #ifdef __ANDROID__
/** /**
@ -290,7 +290,7 @@ bool MapDatabaseSQLite3::saveBlock(const v3s16 &pos, const std::string &data)
void MapDatabaseSQLite3::loadBlock(const v3s16 &pos, std::string *block) void MapDatabaseSQLite3::loadBlock(const v3s16 &pos, std::string *block)
{ {
verifyDatabase(); pingDatabase();
bindPos(m_stmt_read, pos); bindPos(m_stmt_read, pos);
@ -311,7 +311,7 @@ void MapDatabaseSQLite3::loadBlock(const v3s16 &pos, std::string *block)
void MapDatabaseSQLite3::listAllLoadableBlocks(std::vector<v3s16> &dst) void MapDatabaseSQLite3::listAllLoadableBlocks(std::vector<v3s16> &dst)
{ {
verifyDatabase(); pingDatabase();
while (sqlite3_step(m_stmt_list) == SQLITE_ROW) while (sqlite3_step(m_stmt_list) == SQLITE_ROW)
dst.push_back(getIntegerAsBlock(sqlite3_column_int64(m_stmt_list, 0))); dst.push_back(getIntegerAsBlock(sqlite3_column_int64(m_stmt_list, 0)));
@ -439,7 +439,7 @@ void PlayerDatabaseSQLite3::initStatements()
bool PlayerDatabaseSQLite3::playerDataExists(const std::string &name) bool PlayerDatabaseSQLite3::playerDataExists(const std::string &name)
{ {
verifyDatabase(); pingDatabase();
str_to_sqlite(m_stmt_player_load, 1, name); str_to_sqlite(m_stmt_player_load, 1, name);
bool res = (sqlite3_step(m_stmt_player_load) == SQLITE_ROW); bool res = (sqlite3_step(m_stmt_player_load) == SQLITE_ROW);
sqlite3_reset(m_stmt_player_load); sqlite3_reset(m_stmt_player_load);
@ -536,7 +536,7 @@ void PlayerDatabaseSQLite3::savePlayer(RemotePlayer *player)
bool PlayerDatabaseSQLite3::loadPlayer(RemotePlayer *player, PlayerSAO *sao) bool PlayerDatabaseSQLite3::loadPlayer(RemotePlayer *player, PlayerSAO *sao)
{ {
verifyDatabase(); pingDatabase();
str_to_sqlite(m_stmt_player_load, 1, player->getName()); str_to_sqlite(m_stmt_player_load, 1, player->getName());
if (sqlite3_step(m_stmt_player_load) != SQLITE_ROW) { if (sqlite3_step(m_stmt_player_load) != SQLITE_ROW) {
@ -600,7 +600,7 @@ bool PlayerDatabaseSQLite3::removePlayer(const std::string &name)
void PlayerDatabaseSQLite3::listPlayers(std::vector<std::string> &res) void PlayerDatabaseSQLite3::listPlayers(std::vector<std::string> &res)
{ {
verifyDatabase(); pingDatabase();
while (sqlite3_step(m_stmt_player_list) == SQLITE_ROW) while (sqlite3_step(m_stmt_player_list) == SQLITE_ROW)
res.push_back(sqlite_to_string(m_stmt_player_list, 0)); res.push_back(sqlite_to_string(m_stmt_player_list, 0));
@ -673,7 +673,7 @@ void AuthDatabaseSQLite3::initStatements()
bool AuthDatabaseSQLite3::getAuth(const std::string &name, AuthEntry &res) bool AuthDatabaseSQLite3::getAuth(const std::string &name, AuthEntry &res)
{ {
verifyDatabase(); pingDatabase();
str_to_sqlite(m_stmt_read, 1, name); str_to_sqlite(m_stmt_read, 1, name);
if (sqlite3_step(m_stmt_read) != SQLITE_ROW) { if (sqlite3_step(m_stmt_read) != SQLITE_ROW) {
sqlite3_reset(m_stmt_read); sqlite3_reset(m_stmt_read);
@ -735,7 +735,7 @@ bool AuthDatabaseSQLite3::createAuth(AuthEntry &authEntry)
bool AuthDatabaseSQLite3::deleteAuth(const std::string &name) bool AuthDatabaseSQLite3::deleteAuth(const std::string &name)
{ {
verifyDatabase(); pingDatabase();
str_to_sqlite(m_stmt_delete, 1, name); str_to_sqlite(m_stmt_delete, 1, name);
sqlite3_vrfy(sqlite3_step(m_stmt_delete), SQLITE_DONE); sqlite3_vrfy(sqlite3_step(m_stmt_delete), SQLITE_DONE);
@ -749,7 +749,7 @@ bool AuthDatabaseSQLite3::deleteAuth(const std::string &name)
void AuthDatabaseSQLite3::listNames(std::vector<std::string> &res) void AuthDatabaseSQLite3::listNames(std::vector<std::string> &res)
{ {
verifyDatabase(); pingDatabase();
while (sqlite3_step(m_stmt_list_names) == SQLITE_ROW) { while (sqlite3_step(m_stmt_list_names) == SQLITE_ROW) {
res.push_back(sqlite_to_string(m_stmt_list_names, 0)); res.push_back(sqlite_to_string(m_stmt_list_names, 0));

@ -36,13 +36,13 @@ public:
void beginSave(); void beginSave();
void endSave(); void endSave();
// Open and initialize the database if needed
virtual void pingDatabase();
bool initialized() const { return m_initialized; } bool initialized() const { return m_initialized; }
protected: protected:
Database_SQLite3(const std::string &savedir, const std::string &dbname); Database_SQLite3(const std::string &savedir, const std::string &dbname);
// Open and initialize the database if needed
void verifyDatabase();
// Convertors // Convertors
inline void str_to_sqlite(sqlite3_stmt *s, int iCol, const std::string &str) const inline void str_to_sqlite(sqlite3_stmt *s, int iCol, const std::string &str) const
{ {
@ -146,6 +146,8 @@ public:
MapDatabaseSQLite3(const std::string &savedir); MapDatabaseSQLite3(const std::string &savedir);
virtual ~MapDatabaseSQLite3(); virtual ~MapDatabaseSQLite3();
virtual void pingDatabase() { Database_SQLite3::pingDatabase(); }
bool saveBlock(const v3s16 &pos, const std::string &data); bool saveBlock(const v3s16 &pos, const std::string &data);
void loadBlock(const v3s16 &pos, std::string *block); void loadBlock(const v3s16 &pos, std::string *block);
bool deleteBlock(const v3s16 &pos); bool deleteBlock(const v3s16 &pos);
@ -173,6 +175,8 @@ public:
PlayerDatabaseSQLite3(const std::string &savedir); PlayerDatabaseSQLite3(const std::string &savedir);
virtual ~PlayerDatabaseSQLite3(); virtual ~PlayerDatabaseSQLite3();
virtual void pingDatabase() { Database_SQLite3::pingDatabase(); }
void savePlayer(RemotePlayer *player); void savePlayer(RemotePlayer *player);
bool loadPlayer(RemotePlayer *player, PlayerSAO *sao); bool loadPlayer(RemotePlayer *player, PlayerSAO *sao);
bool removePlayer(const std::string &name); bool removePlayer(const std::string &name);
@ -208,6 +212,8 @@ public:
AuthDatabaseSQLite3(const std::string &savedir); AuthDatabaseSQLite3(const std::string &savedir);
virtual ~AuthDatabaseSQLite3(); virtual ~AuthDatabaseSQLite3();
virtual void pingDatabase() { Database_SQLite3::pingDatabase(); }
virtual bool getAuth(const std::string &name, AuthEntry &res); virtual bool getAuth(const std::string &name, AuthEntry &res);
virtual bool saveAuth(const AuthEntry &authEntry); virtual bool saveAuth(const AuthEntry &authEntry);
virtual bool createAuth(AuthEntry &authEntry); virtual bool createAuth(AuthEntry &authEntry);

@ -32,6 +32,7 @@ public:
virtual void beginSave() = 0; virtual void beginSave() = 0;
virtual void endSave() = 0; virtual void endSave() = 0;
virtual bool initialized() const { return true; } virtual bool initialized() const { return true; }
virtual void pingDatabase() {}
}; };
class MapDatabase : public Database class MapDatabase : public Database
@ -57,6 +58,8 @@ class PlayerDatabase
public: public:
virtual ~PlayerDatabase() = default; virtual ~PlayerDatabase() = default;
virtual void pingDatabase() {}
virtual void savePlayer(RemotePlayer *player) = 0; virtual void savePlayer(RemotePlayer *player) = 0;
virtual bool loadPlayer(RemotePlayer *player, PlayerSAO *sao) = 0; virtual bool loadPlayer(RemotePlayer *player, PlayerSAO *sao) = 0;
virtual bool removePlayer(const std::string &name) = 0; virtual bool removePlayer(const std::string &name) = 0;
@ -83,4 +86,5 @@ public:
virtual bool deleteAuth(const std::string &name) = 0; virtual bool deleteAuth(const std::string &name) = 0;
virtual void listNames(std::vector<std::string> &res) = 0; virtual void listNames(std::vector<std::string> &res) = 0;
virtual void reload() = 0; virtual void reload() = 0;
virtual void pingDatabase() {}
}; };

@ -1887,6 +1887,11 @@ MapDatabase *ServerMap::createDatabase(
throw BaseException(std::string("Database backend ") + name + " not supported."); throw BaseException(std::string("Database backend ") + name + " not supported.");
} }
void ServerMap::pingDatabase()
{
dbase->pingDatabase();
}
void ServerMap::beginSave() void ServerMap::beginSave()
{ {
dbase->beginSave(); dbase->beginSave();

@ -385,6 +385,7 @@ public:
Database functions Database functions
*/ */
static MapDatabase *createDatabase(const std::string &name, const std::string &savedir, Settings &conf); static MapDatabase *createDatabase(const std::string &name, const std::string &savedir, Settings &conf);
void pingDatabase();
// Call these before and after saving of blocks // Call these before and after saving of blocks
void beginSave(); void beginSave();

@ -1219,6 +1219,11 @@ void ServerEnvironment::step(float dtime)
} }
} }
if (m_database_check_interval.step(dtime, 10.0f)) {
m_auth_database->pingDatabase();
m_player_database->pingDatabase();
m_map->pingDatabase();
}
/* /*
Manage active block list Manage active block list
*/ */

@ -435,6 +435,7 @@ private:
IntervalLimiter m_object_management_interval; IntervalLimiter m_object_management_interval;
// List of active blocks // List of active blocks
ActiveBlockList m_active_blocks; ActiveBlockList m_active_blocks;
IntervalLimiter m_database_check_interval;
IntervalLimiter m_active_blocks_management_interval; IntervalLimiter m_active_blocks_management_interval;
IntervalLimiter m_active_block_modifier_interval; IntervalLimiter m_active_block_modifier_interval;
IntervalLimiter m_active_blocks_nodemetadata_interval; IntervalLimiter m_active_blocks_nodemetadata_interval;