[Database] Address deadlock in player events (#2974)

* DB mutex testing

* Mutex tweaks, native string escaping
This commit is contained in:
Chris Miles 2023-02-20 22:32:29 -06:00 committed by GitHub
parent 6a668f8aa5
commit 33bb5aa8e5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 27 additions and 14 deletions

View File

@ -70,17 +70,20 @@ DBcore::~DBcore()
// Sends the MySQL server a keepalive // Sends the MySQL server a keepalive
void DBcore::ping() void DBcore::ping()
{ {
if (!MDatabase.trylock()) { if (!m_query_lock.try_lock()) {
// well, if's it's locked, someone's using it. If someone's using it, it doesnt need a keepalive // well, if's it's locked, someone's using it. If someone's using it, it doesnt need a keepalive
return; return;
} }
mysql_ping(&mysql); mysql_ping(&mysql);
MDatabase.unlock(); m_query_lock.unlock();
} }
MySQLRequestResult DBcore::QueryDatabase(std::string query, bool retryOnFailureOnce) MySQLRequestResult DBcore::QueryDatabase(std::string query, bool retryOnFailureOnce)
{ {
return QueryDatabase(query.c_str(), query.length(), retryOnFailureOnce); m_query_lock.lock();
auto r = QueryDatabase(query.c_str(), query.length(), retryOnFailureOnce);
m_query_lock.unlock();
return r;
} }
bool DBcore::DoesTableExist(std::string table_name) bool DBcore::DoesTableExist(std::string table_name)
@ -95,15 +98,11 @@ MySQLRequestResult DBcore::QueryDatabase(const char *query, uint32 querylen, boo
BenchTimer timer; BenchTimer timer;
timer.reset(); timer.reset();
LockMutex lock(&MDatabase);
// Reconnect if we are not connected before hand. // Reconnect if we are not connected before hand.
if (pStatus != Connected) { if (pStatus != Connected) {
Open(); Open();
} }
// request query. != 0 indicates some kind of error. // request query. != 0 indicates some kind of error.
if (mysql_real_query(&mysql, query, querylen) != 0) { if (mysql_real_query(&mysql, query, querylen) != 0) {
unsigned int errorNumber = mysql_errno(&mysql); unsigned int errorNumber = mysql_errno(&mysql);
@ -299,3 +298,12 @@ void DBcore::SetOriginHost(const std::string &origin_host)
{ {
DBcore::origin_host = origin_host; DBcore::origin_host = origin_host;
} }
std::string DBcore::Escape(const std::string& s)
{
const std::size_t s_len = s.length();
std::vector<char> temp((s_len * 2) + 1, '\0');
mysql_real_escape_string(&mysql, temp.data(), s.c_str(), s_len);
return temp.data();
}

View File

@ -12,6 +12,7 @@
#include <mysql.h> #include <mysql.h>
#include <string.h> #include <string.h>
#include <mutex>
class DBcore { class DBcore {
public: public:
@ -27,6 +28,7 @@ public:
void TransactionBegin(); void TransactionBegin();
void TransactionCommit(); void TransactionCommit();
void TransactionRollback(); void TransactionRollback();
std::string Escape(const std::string& s);
uint32 DoEscapeString(char *tobuf, const char *frombuf, uint32 fromlen); uint32 DoEscapeString(char *tobuf, const char *frombuf, uint32 fromlen);
void ping(); void ping();
MYSQL *getMySQL() { return &mysql; } MYSQL *getMySQL() { return &mysql; }
@ -57,6 +59,8 @@ private:
Mutex MDatabase; Mutex MDatabase;
eStatus pStatus; eStatus pStatus;
std::mutex m_query_lock{};
std::string origin_host; std::string origin_host;
char *pHost; char *pHost;

View File

@ -113,7 +113,9 @@ bool PlayerEventLogs::IsEventEnabled(PlayerEvent::EventType event)
// this processes any current player events on the queue // this processes any current player events on the queue
void PlayerEventLogs::ProcessBatchQueue() void PlayerEventLogs::ProcessBatchQueue()
{ {
m_batch_queue_lock.lock();
if (m_record_batch_queue.empty()) { if (m_record_batch_queue.empty()) {
m_batch_queue_lock.unlock();
return; return;
} }
@ -128,7 +130,6 @@ void PlayerEventLogs::ProcessBatchQueue()
); );
// empty // empty
m_batch_queue_lock.lock();
m_record_batch_queue = {}; m_record_batch_queue = {};
m_batch_queue_lock.unlock(); m_batch_queue_lock.unlock();
} }

View File

@ -240,8 +240,8 @@ public:
v.push_back(columns[7] + " = " + std::to_string(e.z)); v.push_back(columns[7] + " = " + std::to_string(e.z));
v.push_back(columns[8] + " = " + std::to_string(e.heading)); v.push_back(columns[8] + " = " + std::to_string(e.heading));
v.push_back(columns[9] + " = " + std::to_string(e.event_type_id)); v.push_back(columns[9] + " = " + std::to_string(e.event_type_id));
v.push_back(columns[10] + " = '" + Strings::Escape(e.event_type_name) + "'"); v.push_back(columns[10] + " = '" + db.Escape(e.event_type_name) + "'");
v.push_back(columns[11] + " = '" + Strings::Escape(e.event_data) + "'"); v.push_back(columns[11] + " = '" + db.Escape(e.event_data) + "'");
v.push_back(columns[12] + " = FROM_UNIXTIME(" + (e.created_at > 0 ? std::to_string(e.created_at) : "null") + ")"); v.push_back(columns[12] + " = FROM_UNIXTIME(" + (e.created_at > 0 ? std::to_string(e.created_at) : "null") + ")");
auto results = db.QueryDatabase( auto results = db.QueryDatabase(
@ -274,8 +274,8 @@ public:
v.push_back(std::to_string(e.z)); v.push_back(std::to_string(e.z));
v.push_back(std::to_string(e.heading)); v.push_back(std::to_string(e.heading));
v.push_back(std::to_string(e.event_type_id)); v.push_back(std::to_string(e.event_type_id));
v.push_back("'" + Strings::Escape(e.event_type_name) + "'"); v.push_back("'" + db.Escape(e.event_type_name) + "'");
v.push_back("'" + Strings::Escape(e.event_data) + "'"); v.push_back("'" + db.Escape(e.event_data) + "'");
v.push_back("FROM_UNIXTIME(" + (e.created_at > 0 ? std::to_string(e.created_at) : "null") + ")"); v.push_back("FROM_UNIXTIME(" + (e.created_at > 0 ? std::to_string(e.created_at) : "null") + ")");
auto results = db.QueryDatabase( auto results = db.QueryDatabase(
@ -316,8 +316,8 @@ public:
v.push_back(std::to_string(e.z)); v.push_back(std::to_string(e.z));
v.push_back(std::to_string(e.heading)); v.push_back(std::to_string(e.heading));
v.push_back(std::to_string(e.event_type_id)); v.push_back(std::to_string(e.event_type_id));
v.push_back("'" + Strings::Escape(e.event_type_name) + "'"); v.push_back("'" + db.Escape(e.event_type_name) + "'");
v.push_back("'" + Strings::Escape(e.event_data) + "'"); v.push_back("'" + db.Escape(e.event_data) + "'");
v.push_back("FROM_UNIXTIME(" + (e.created_at > 0 ? std::to_string(e.created_at) : "null") + ")"); v.push_back("FROM_UNIXTIME(" + (e.created_at > 0 ? std::to_string(e.created_at) : "null") + ")");
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")"); insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");