mirror of
https://github.com/EQEmu/Server.git
synced 2025-12-12 09:31:30 +00:00
[Database] Address deadlock in player events (#2974)
* DB mutex testing * Mutex tweaks, native string escaping
This commit is contained in:
parent
6a668f8aa5
commit
33bb5aa8e5
@ -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();
|
||||||
|
}
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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) + ")");
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user