Switch database mutex to recursive because we copy it everywhere

... and I have no idea if any of the calls are re-entrant. yay.
This commit is contained in:
brainiac 2026-04-04 17:34:59 -07:00
parent 7aa669d041
commit d1d5c5dd7a
8 changed files with 17 additions and 16 deletions

View File

@ -34,7 +34,7 @@
DBcore::DBcore() DBcore::DBcore()
: mysql(mysql_init(nullptr)) : mysql(mysql_init(nullptr))
, m_mutex(std::make_shared<std::mutex>()) , m_mutex(std::make_shared<Mutex>())
{ {
} }
@ -220,12 +220,12 @@ bool DBcore::Open(
bool DBcore::Open(uint32 *errnum, char *errbuf) bool DBcore::Open(uint32 *errnum, char *errbuf)
{ {
// Expects m_mutex to already be locked.
if (errbuf) { if (errbuf) {
errbuf[0] = 0; errbuf[0] = 0;
} }
std::scoped_lock lock(*m_mutex);
if (GetStatus() == Connected) { if (GetStatus() == Connected) {
return true; return true;
} }
@ -294,7 +294,7 @@ std::string DBcore::Escape(const std::string& s)
return temp.data(); return temp.data();
} }
void DBcore::SetMutex(const std::shared_ptr<std::mutex>& mutex) void DBcore::SetMutex(const std::shared_ptr<Mutex>& mutex)
{ {
DBcore::m_mutex = mutex; DBcore::m_mutex = mutex;
} }

View File

@ -36,6 +36,8 @@ public:
Closed, Connected, Error Closed, Connected, Error
}; };
using Mutex = std::recursive_mutex;
DBcore(); DBcore();
~DBcore(); ~DBcore();
eStatus GetStatus() { return pStatus; } eStatus GetStatus() { return pStatus; }
@ -59,7 +61,7 @@ public:
mysql = o.mysql; mysql = o.mysql;
mysqlOwner = false; mysqlOwner = false;
} }
void SetMutex(const std::shared_ptr<std::mutex>& mutex); void SetMutex(const std::shared_ptr<Mutex>& mutex);
// only safe on connections shared with other threads if results buffered // only safe on connections shared with other threads if results buffered
// unsafe to use off main thread due to internal server logging // unsafe to use off main thread due to internal server logging
@ -86,8 +88,7 @@ private:
bool mysqlOwner = true; bool mysqlOwner = true;
eStatus pStatus = Closed; eStatus pStatus = Closed;
std::shared_ptr<std::mutex> m_mutex; std::shared_ptr<Mutex> m_mutex;
std::mutex m_query_lock;
std::string origin_host; std::string origin_host;

View File

@ -95,7 +95,7 @@ void TaskScheduler::ProcessWork()
m_data->cv.wait(lock, m_data->cv.wait(lock,
[this] [this]
{ {
return !m_data->running || m_data->tasks.empty(); return !m_data->running || !m_data->tasks.empty();
}); });
if (!m_data->running) if (!m_data->running)

View File

@ -35,7 +35,7 @@ void PreparedStmt::StmtDeleter::operator()(MYSQL_STMT* stmt) noexcept
mysql_stmt_close(stmt); mysql_stmt_close(stmt);
} }
PreparedStmt::PreparedStmt(MYSQL& mysql, std::string query, std::mutex& mutex, StmtOptions opts) PreparedStmt::PreparedStmt(MYSQL& mysql, std::string query, DBcore::Mutex& mutex, StmtOptions opts)
: m_stmt(mysql_stmt_init(&mysql), { mutex }) : m_stmt(mysql_stmt_init(&mysql), { mutex })
, m_query(std::move(query)) , m_query(std::move(query))
, m_options(opts) , m_options(opts)

View File

@ -17,8 +17,8 @@
*/ */
#pragma once #pragma once
#include "common/dbcore.h"
#include "mysql.h"
#include <cassert> #include <cassert>
#include <cstring> #include <cstring>
#include <memory> #include <memory>
@ -185,7 +185,7 @@ public:
int64_t, uint64_t, float, double, bool, std::string_view, std::nullptr_t>; int64_t, uint64_t, float, double, bool, std::string_view, std::nullptr_t>;
PreparedStmt() = delete; PreparedStmt() = delete;
PreparedStmt(MYSQL& mysql, std::string query, std::mutex& mutex, StmtOptions opts = {}); PreparedStmt(MYSQL& mysql, std::string query, DBcore::Mutex& mutex, StmtOptions opts = {});
const std::string& GetQuery() const { return m_query; } const std::string& GetQuery() const { return m_query; }
StmtOptions GetOptions() const { return m_options; } StmtOptions GetOptions() const { return m_options; }
@ -221,7 +221,7 @@ private:
struct StmtDeleter struct StmtDeleter
{ {
std::mutex& mutex; DBcore::Mutex& mutex;
void operator()(MYSQL_STMT* stmt) noexcept; void operator()(MYSQL_STMT* stmt) noexcept;
}; };
@ -235,7 +235,7 @@ private:
std::string m_query; std::string m_query;
StmtOptions m_options = {}; StmtOptions m_options = {};
bool m_need_bind = true; bool m_need_bind = true;
std::mutex& m_mutex; // connection mutex DBcore::Mutex& m_mutex; // connection mutex
}; };
} // namespace mysql } // namespace mysql

View File

@ -76,7 +76,7 @@ void WorldserverCLI::TestDatabaseConcurrency(int argc, char **argv, argh::parser
return; return;
} }
std::shared_ptr<std::mutex> sharedMutex = std::make_shared<std::mutex>(); std::shared_ptr<DBcore::Mutex> sharedMutex = std::make_shared<DBcore::Mutex>();
db.SetMutex(sharedMutex); db.SetMutex(sharedMutex);

View File

@ -180,7 +180,7 @@ bool WorldBoot::LoadDatabaseConnections()
// when database and content_db share the same underlying mysql connection // when database and content_db share the same underlying mysql connection
// it needs to be protected by a shared mutex otherwise we produce concurrency issues // it needs to be protected by a shared mutex otherwise we produce concurrency issues
// when database actions are occurring in different threads // when database actions are occurring in different threads
std::shared_ptr<std::mutex> sharedMutex = std::make_shared<std::mutex>(); std::shared_ptr<DBcore::Mutex> sharedMutex = std::make_shared<DBcore::Mutex>();
database.SetMutex(sharedMutex); database.SetMutex(sharedMutex);
content_db.SetMutex(sharedMutex); content_db.SetMutex(sharedMutex);
} }

View File

@ -246,7 +246,7 @@ int main(int argc, char **argv)
// when database and content_db share the same underlying mysql connection // when database and content_db share the same underlying mysql connection
// it needs to be protected by a shared mutex otherwise we produce concurrency issues // it needs to be protected by a shared mutex otherwise we produce concurrency issues
// when database actions are occurring in different threads // when database actions are occurring in different threads
std::shared_ptr<std::mutex> sharedMutex = std::make_shared<std::mutex>(); std::shared_ptr<DBcore::Mutex> sharedMutex = std::make_shared<DBcore::Mutex>();
database.SetMutex(sharedMutex); database.SetMutex(sharedMutex);
content_db.SetMutex(sharedMutex); content_db.SetMutex(sharedMutex);
} }