From 746f5ea58d204a3d74c531c28214b72b7837f116 Mon Sep 17 00:00:00 2001 From: KimLS Date: Sun, 5 Feb 2023 02:31:08 -0800 Subject: [PATCH 1/5] MYSQL objects cannot be copied in a well defined way, this removes the copy and replaces it with another connection --- client_files/export/main.cpp | 11 ++++++++++- client_files/import/main.cpp | 11 ++++++++++- common/dbcore.cpp | 5 ----- common/dbcore.h | 2 -- shared_memory/main.cpp | 11 ++++++++++- world/world_boot.cpp | 12 +++++++++++- zone/main.cpp | 12 +++++++++++- 7 files changed, 52 insertions(+), 12 deletions(-) diff --git a/client_files/export/main.cpp b/client_files/export/main.cpp index 505a4ac059..1aab8105a1 100644 --- a/client_files/export/main.cpp +++ b/client_files/export/main.cpp @@ -86,7 +86,16 @@ int main(int argc, char **argv) return 1; } } else { - content_db.SetMysql(database.getMySQL()); + if (!content_db.Connect( + Config->DatabaseHost.c_str(), + Config->DatabaseUsername.c_str(), + Config->DatabasePassword.c_str(), + Config->DatabaseDB.c_str(), + Config->DatabasePort + )) { + LogError("Cannot continue without a content database connection"); + return 1; + } } LogSys.SetDatabase(&database) diff --git a/client_files/import/main.cpp b/client_files/import/main.cpp index c80ed81940..c4d71389d2 100644 --- a/client_files/import/main.cpp +++ b/client_files/import/main.cpp @@ -83,7 +83,16 @@ int main(int argc, char **argv) { return 1; } } else { - content_db.SetMysql(database.getMySQL()); + if (!content_db.Connect( + Config->DatabaseHost.c_str(), + Config->DatabaseUsername.c_str(), + Config->DatabasePassword.c_str(), + Config->DatabaseDB.c_str(), + Config->DatabasePort + )) { + LogError("Cannot continue without a content database connection"); + return 1; + } } LogSys.SetDatabase(&database) diff --git a/common/dbcore.cpp b/common/dbcore.cpp index 1a4fbef7a2..ae854f8b3c 100644 --- a/common/dbcore.cpp +++ b/common/dbcore.cpp @@ -284,11 +284,6 @@ bool DBcore::Open(uint32 *errnum, char *errbuf) } } -void DBcore::SetMysql(MYSQL *mysql) -{ - DBcore::mysql = *mysql; -} - const std::string &DBcore::GetOriginHost() const { return origin_host; diff --git a/common/dbcore.h b/common/dbcore.h index 90a5ca5055..784c224caf 100644 --- a/common/dbcore.h +++ b/common/dbcore.h @@ -31,8 +31,6 @@ class DBcore { std::string Escape(const std::string& s); uint32 DoEscapeString(char *tobuf, const char *frombuf, uint32 fromlen); void ping(); - MYSQL *getMySQL() { return &mysql; } - void SetMysql(MYSQL *mysql); const std::string &GetOriginHost() const; void SetOriginHost(const std::string &origin_host); diff --git a/shared_memory/main.cpp b/shared_memory/main.cpp index 98a9c46b48..1ec904c403 100644 --- a/shared_memory/main.cpp +++ b/shared_memory/main.cpp @@ -124,7 +124,16 @@ int main(int argc, char **argv) return 1; } } else { - content_db.SetMysql(database.getMySQL()); + if (!content_db.Connect( + Config->DatabaseHost.c_str(), + Config->DatabaseUsername.c_str(), + Config->DatabasePassword.c_str(), + Config->DatabaseDB.c_str(), + Config->DatabasePort + )) { + LogError("Cannot continue without a content database connection"); + return 1; + } } LogSys.SetDatabase(&database) diff --git a/world/world_boot.cpp b/world/world_boot.cpp index 00caf77616..c0f36cbc9f 100644 --- a/world/world_boot.cpp +++ b/world/world_boot.cpp @@ -153,7 +153,17 @@ bool WorldBoot::LoadDatabaseConnections() } } else { - content_db.SetMysql(database.getMySQL()); + if (!content_db.Connect( + c->DatabaseHost.c_str(), + c->DatabaseUsername.c_str(), + c->DatabasePassword.c_str(), + c->DatabaseDB.c_str(), + c->DatabasePort, + "content" + )) { + LogError("Cannot continue without a content database connection"); + return false; + } } return true; diff --git a/zone/main.cpp b/zone/main.cpp index 7aa9d3ce3d..a3a2e14232 100644 --- a/zone/main.cpp +++ b/zone/main.cpp @@ -258,7 +258,17 @@ int main(int argc, char** argv) { return 1; } } else { - content_db.SetMysql(database.getMySQL()); + if (!content_db.Connect( + Config->DatabaseHost.c_str(), + Config->DatabaseUsername.c_str(), + Config->DatabasePassword.c_str(), + Config->DatabaseDB.c_str(), + Config->DatabasePort, + "content" + )) { + LogError("Cannot continue without a content database connection"); + return 1; + } } /* Register Log System and Settings */ From e10beae24629841a090102337c49ff8603af7077 Mon Sep 17 00:00:00 2001 From: KimLS Date: Mon, 6 Feb 2023 23:30:07 -0800 Subject: [PATCH 2/5] Change to share underlying pointers. --- client_files/export/main.cpp | 11 +------- client_files/import/main.cpp | 11 +------- common/dbcore.cpp | 52 +++++++++++++++++------------------- common/dbcore.h | 5 +++- shared_memory/main.cpp | 11 +------- world/world_boot.cpp | 12 +-------- zone/main.cpp | 12 +-------- 7 files changed, 33 insertions(+), 81 deletions(-) diff --git a/client_files/export/main.cpp b/client_files/export/main.cpp index 1aab8105a1..67d19326f4 100644 --- a/client_files/export/main.cpp +++ b/client_files/export/main.cpp @@ -86,16 +86,7 @@ int main(int argc, char **argv) return 1; } } else { - if (!content_db.Connect( - Config->DatabaseHost.c_str(), - Config->DatabaseUsername.c_str(), - Config->DatabasePassword.c_str(), - Config->DatabaseDB.c_str(), - Config->DatabasePort - )) { - LogError("Cannot continue without a content database connection"); - return 1; - } + content_db.SetMySQL(database); } LogSys.SetDatabase(&database) diff --git a/client_files/import/main.cpp b/client_files/import/main.cpp index c4d71389d2..6e23821ab5 100644 --- a/client_files/import/main.cpp +++ b/client_files/import/main.cpp @@ -83,16 +83,7 @@ int main(int argc, char **argv) { return 1; } } else { - if (!content_db.Connect( - Config->DatabaseHost.c_str(), - Config->DatabaseUsername.c_str(), - Config->DatabasePassword.c_str(), - Config->DatabaseDB.c_str(), - Config->DatabasePort - )) { - LogError("Cannot continue without a content database connection"); - return 1; - } + content_db.SetMySQL(database); } LogSys.SetDatabase(&database) diff --git a/common/dbcore.cpp b/common/dbcore.cpp index ae854f8b3c..e06f92490f 100644 --- a/common/dbcore.cpp +++ b/common/dbcore.cpp @@ -34,7 +34,8 @@ DBcore::DBcore() { - mysql_init(&mysql); + mysql = mysql_init(nullptr); + mysqlOwner = true; pHost = nullptr; pUser = nullptr; pPassword = nullptr; @@ -42,6 +43,7 @@ DBcore::DBcore() pCompress = false; pSSL = false; pStatus = Closed; + } DBcore::~DBcore() @@ -51,16 +53,10 @@ DBcore::~DBcore() * are re-using the default database connection pointer when we dont have an * external configuration setup ex: (content_database) */ - std::string mysql_connection_host; - if (mysql.host) { - mysql_connection_host = mysql.host; - } - - if (GetOriginHost() != mysql_connection_host) { - return; + if (mysqlOwner) { + mysql_close(mysql); } - mysql_close(&mysql); safe_delete_array(pHost); safe_delete_array(pUser); safe_delete_array(pPassword); @@ -74,7 +70,7 @@ void DBcore::ping() // well, if's it's locked, someone's using it. If someone's using it, it doesnt need a keepalive return; } - mysql_ping(&mysql); + mysql_ping(mysql); MDatabase.unlock(); } @@ -104,8 +100,8 @@ MySQLRequestResult DBcore::QueryDatabase(const char *query, uint32 querylen, boo } // request query. != 0 indicates some kind of error. - if (mysql_real_query(&mysql, query, querylen) != 0) { - unsigned int errorNumber = mysql_errno(&mysql); + if (mysql_real_query(mysql, query, querylen) != 0) { + unsigned int errorNumber = mysql_errno(mysql); if (errorNumber == CR_SERVER_GONE_ERROR) { pStatus = Error; @@ -129,26 +125,26 @@ MySQLRequestResult DBcore::QueryDatabase(const char *query, uint32 querylen, boo auto errorBuffer = new char[MYSQL_ERRMSG_SIZE]; - snprintf(errorBuffer, MYSQL_ERRMSG_SIZE, "#%i: %s", mysql_errno(&mysql), mysql_error(&mysql)); + snprintf(errorBuffer, MYSQL_ERRMSG_SIZE, "#%i: %s", mysql_errno(mysql), mysql_error(mysql)); - return MySQLRequestResult(nullptr, 0, 0, 0, 0, (uint32) mysql_errno(&mysql), errorBuffer); + return MySQLRequestResult(nullptr, 0, 0, 0, 0, (uint32) mysql_errno(mysql), errorBuffer); } auto errorBuffer = new char[MYSQL_ERRMSG_SIZE]; - snprintf(errorBuffer, MYSQL_ERRMSG_SIZE, "#%i: %s", mysql_errno(&mysql), mysql_error(&mysql)); + snprintf(errorBuffer, MYSQL_ERRMSG_SIZE, "#%i: %s", mysql_errno(mysql), mysql_error(mysql)); /** * Error logging */ - if (mysql_errno(&mysql) > 0 && strlen(query) > 0) { - LogMySQLError("[{}] [{}]\n[{}]", mysql_errno(&mysql), mysql_error(&mysql), query); + if (mysql_errno(mysql) > 0 && strlen(query) > 0) { + LogMySQLError("[{}] [{}]\n[{}]", mysql_errno(mysql), mysql_error(mysql), query); } - return MySQLRequestResult(nullptr, 0, 0, 0, 0, mysql_errno(&mysql), errorBuffer); + return MySQLRequestResult(nullptr, 0, 0, 0, 0, mysql_errno(mysql), errorBuffer); } // successful query. get results. - MYSQL_RES *res = mysql_store_result(&mysql); + MYSQL_RES *res = mysql_store_result(mysql); uint32 rowCount = 0; if (res != nullptr) { @@ -157,10 +153,10 @@ MySQLRequestResult DBcore::QueryDatabase(const char *query, uint32 querylen, boo MySQLRequestResult requestResult( res, - (uint32) mysql_affected_rows(&mysql), + (uint32) mysql_affected_rows(mysql), rowCount, - (uint32) mysql_field_count(&mysql), - (uint32) mysql_insert_id(&mysql) + (uint32) mysql_field_count(mysql), + (uint32) mysql_insert_id(mysql) ); if (LogSys.log_settings[Logs::MySQLQuery].is_category_enabled == 1) { @@ -206,7 +202,7 @@ uint32 DBcore::DoEscapeString(char *tobuf, const char *frombuf, uint32 fromlen) { // No good reason to lock the DB, we only need it in the first place to check char encoding. // LockMutex lock(&MDatabase); - return mysql_real_escape_string(&mysql, tobuf, frombuf, fromlen); + return mysql_real_escape_string(mysql, tobuf, frombuf, fromlen); } bool DBcore::Open( @@ -246,8 +242,8 @@ bool DBcore::Open(uint32 *errnum, char *errbuf) return true; } if (GetStatus() == Error) { - mysql_close(&mysql); - mysql_init(&mysql); // Initialize structure again + mysql_close(mysql); + mysql_init(mysql); // Initialize structure again } if (!pHost) { return false; @@ -264,7 +260,7 @@ bool DBcore::Open(uint32 *errnum, char *errbuf) if (pSSL) { flags |= CLIENT_SSL; } - if (mysql_real_connect(&mysql, pHost, pUser, pPassword, pDatabase, pPort, 0, flags)) { + if (mysql_real_connect(mysql, pHost, pUser, pPassword, pDatabase, pPort, 0, flags)) { pStatus = Connected; std::string connected_origin_host = pHost; @@ -274,10 +270,10 @@ bool DBcore::Open(uint32 *errnum, char *errbuf) } else { if (errnum) { - *errnum = mysql_errno(&mysql); + *errnum = mysql_errno(mysql); } if (errbuf) { - snprintf(errbuf, MYSQL_ERRMSG_SIZE, "#%i: %s", mysql_errno(&mysql), mysql_error(&mysql)); + snprintf(errbuf, MYSQL_ERRMSG_SIZE, "#%i: %s", mysql_errno(mysql), mysql_error(mysql)); } pStatus = Error; return false; diff --git a/common/dbcore.h b/common/dbcore.h index 784c224caf..0b78d0624d 100644 --- a/common/dbcore.h +++ b/common/dbcore.h @@ -37,6 +37,8 @@ class DBcore { bool DoesTableExist(std::string table_name); + void SetMySQL(const DBcore& o) { mysql = o.mysql; mysqlOwner = false; } + protected: bool Open( const char *iHost, @@ -53,7 +55,8 @@ class DBcore { private: bool Open(uint32 *errnum = nullptr, char *errbuf = nullptr); - MYSQL mysql; + MYSQL* mysql; + bool mysqlOwner; Mutex MDatabase; eStatus pStatus; diff --git a/shared_memory/main.cpp b/shared_memory/main.cpp index 1ec904c403..b5473d43fc 100644 --- a/shared_memory/main.cpp +++ b/shared_memory/main.cpp @@ -124,16 +124,7 @@ int main(int argc, char **argv) return 1; } } else { - if (!content_db.Connect( - Config->DatabaseHost.c_str(), - Config->DatabaseUsername.c_str(), - Config->DatabasePassword.c_str(), - Config->DatabaseDB.c_str(), - Config->DatabasePort - )) { - LogError("Cannot continue without a content database connection"); - return 1; - } + content_db.SetMySQL(database); } LogSys.SetDatabase(&database) diff --git a/world/world_boot.cpp b/world/world_boot.cpp index c0f36cbc9f..fe3249aaf8 100644 --- a/world/world_boot.cpp +++ b/world/world_boot.cpp @@ -153,17 +153,7 @@ bool WorldBoot::LoadDatabaseConnections() } } else { - if (!content_db.Connect( - c->DatabaseHost.c_str(), - c->DatabaseUsername.c_str(), - c->DatabasePassword.c_str(), - c->DatabaseDB.c_str(), - c->DatabasePort, - "content" - )) { - LogError("Cannot continue without a content database connection"); - return false; - } + content_db.SetMySQL(database); } return true; diff --git a/zone/main.cpp b/zone/main.cpp index a3a2e14232..d004ea2313 100644 --- a/zone/main.cpp +++ b/zone/main.cpp @@ -258,17 +258,7 @@ int main(int argc, char** argv) { return 1; } } else { - if (!content_db.Connect( - Config->DatabaseHost.c_str(), - Config->DatabaseUsername.c_str(), - Config->DatabasePassword.c_str(), - Config->DatabaseDB.c_str(), - Config->DatabasePort, - "content" - )) { - LogError("Cannot continue without a content database connection"); - return 1; - } + content_db.SetMySQL(database); } /* Register Log System and Settings */ From 861b688163a7121f57824f1ff41cc1996d177207 Mon Sep 17 00:00:00 2001 From: Akkadius Date: Fri, 24 Feb 2023 17:53:54 -0600 Subject: [PATCH 3/5] Push up mutex changes --- common/dbcore.cpp | 19 +++++--- common/dbcore.h | 11 +++-- world/cli/database_concurrency.cpp | 73 ++++++++++++++++++++++++++++++ world/main.cpp | 2 + world/world_boot.cpp | 16 +++++-- world/world_boot.h | 1 + world/world_server_cli.cpp | 2 + world/world_server_cli.h | 1 + zone/main.cpp | 14 ++++-- 9 files changed, 124 insertions(+), 15 deletions(-) create mode 100644 world/cli/database_concurrency.cpp diff --git a/common/dbcore.cpp b/common/dbcore.cpp index e06f92490f..02917d2db6 100644 --- a/common/dbcore.cpp +++ b/common/dbcore.cpp @@ -43,7 +43,7 @@ DBcore::DBcore() pCompress = false; pSSL = false; pStatus = Closed; - + m_mutex = new Mutex; } DBcore::~DBcore() @@ -66,12 +66,12 @@ DBcore::~DBcore() // Sends the MySQL server a keepalive void DBcore::ping() { - if (!MDatabase.trylock()) { + if (!m_mutex->trylock()) { // well, if's it's locked, someone's using it. If someone's using it, it doesnt need a keepalive return; } mysql_ping(mysql); - MDatabase.unlock(); + m_mutex->unlock(); } MySQLRequestResult DBcore::QueryDatabase(std::string query, bool retryOnFailureOnce) @@ -92,7 +92,7 @@ MySQLRequestResult DBcore::QueryDatabase(const char *query, uint32 querylen, boo BenchTimer timer; timer.reset(); - LockMutex lock(&MDatabase); + LockMutex lock(m_mutex); // Reconnect if we are not connected before hand. if (pStatus != Connected) { @@ -217,7 +217,7 @@ bool DBcore::Open( bool iSSL ) { - LockMutex lock(&MDatabase); + LockMutex lock(m_mutex); safe_delete_array(pHost); safe_delete_array(pUser); safe_delete_array(pPassword); @@ -237,7 +237,7 @@ bool DBcore::Open(uint32 *errnum, char *errbuf) if (errbuf) { errbuf[0] = 0; } - LockMutex lock(&MDatabase); + LockMutex lock(m_mutex); if (GetStatus() == Connected) { return true; } @@ -298,3 +298,10 @@ std::string DBcore::Escape(const std::string& s) return temp.data(); } + +void DBcore::SetMutex(Mutex *mutex) +{ + safe_delete(m_mutex); + + DBcore::m_mutex = mutex; +} diff --git a/common/dbcore.h b/common/dbcore.h index 0b78d0624d..c1e28bb421 100644 --- a/common/dbcore.h +++ b/common/dbcore.h @@ -37,7 +37,12 @@ class DBcore { bool DoesTableExist(std::string table_name); - void SetMySQL(const DBcore& o) { mysql = o.mysql; mysqlOwner = false; } + void SetMySQL(const DBcore &o) + { + mysql = o.mysql; + mysqlOwner = false; + } + void SetMutex(Mutex *mutex); protected: bool Open( @@ -56,8 +61,8 @@ class DBcore { bool Open(uint32 *errnum = nullptr, char *errbuf = nullptr); MYSQL* mysql; - bool mysqlOwner; - Mutex MDatabase; + bool mysqlOwner; + Mutex *m_mutex; eStatus pStatus; std::mutex m_query_lock{}; diff --git a/world/cli/database_concurrency.cpp b/world/cli/database_concurrency.cpp new file mode 100644 index 0000000000..bb20f4eba0 --- /dev/null +++ b/world/cli/database_concurrency.cpp @@ -0,0 +1,73 @@ +#include +#include "../../common/repositories/zone_repository.h" +#include "../../common/eqemu_config.h" +#include + +Database db; +Database db2; + +volatile sig_atomic_t stop; +void inthand(int signum) { + stop = 1; +} + +[[noreturn]] void DatabaseTest() +{ + while (true) { + LogInfo("DatabaseTest Query"); + db.QueryDatabase("SELECT 1"); + } +} + +[[noreturn]] void DatabaseTestSecondConnection() +{ + while (true) { + LogInfo("DatabaseTest Query"); + db2.QueryDatabase("SELECT 1"); + } +} + + +void WorldserverCLI::TestDatabaseConcurrency(int argc, char **argv, argh::parser &cmd, std::string &description) +{ + description = "Test command to test database concurrency"; + + if (cmd[{"-h", "--help"}]) { + return; + } + + signal(SIGINT, inthand); + + LogInfo("Database test"); + + auto mutex = new Mutex; + + auto c = EQEmuConfig::get(); + LogInfo("Connecting to MySQL"); + if (!db.Connect( + c->DatabaseHost.c_str(), + c->DatabaseUsername.c_str(), + c->DatabasePassword.c_str(), + c->DatabaseDB.c_str(), + c->DatabasePort + )) { + LogError("Cannot continue without a database connection"); + return; + } + + db.SetMutex(mutex); + + db2.SetMySQL(db); + + db2.SetMutex(mutex); + + std::thread(DatabaseTest).detach(); + std::thread(DatabaseTest).detach(); + std::thread(DatabaseTestSecondConnection).detach(); + + while (!stop) { + + } + + safe_delete(mutex); +} diff --git a/world/main.cpp b/world/main.cpp index 3aa175899b..de97693d89 100644 --- a/world/main.cpp +++ b/world/main.cpp @@ -478,6 +478,8 @@ int main(int argc, char **argv) LogInfo("Signaling HTTP service to stop"); LogSys.CloseFileLogs(); + WorldBoot::Shutdown(); + return 0; } diff --git a/world/world_boot.cpp b/world/world_boot.cpp index fe3249aaf8..286d689eb9 100644 --- a/world/world_boot.cpp +++ b/world/world_boot.cpp @@ -30,6 +30,8 @@ extern ZSList zoneserver_list; extern WorldConfig Config; +auto mutex = new Mutex; + void WorldBoot::GMSayHookCallBackProcessWorld(uint16 log_category, const char *func, std::string message) { // we don't want to loop up with chat messages @@ -136,9 +138,7 @@ bool WorldBoot::LoadDatabaseConnections() return false; } - /** - * Multi-tenancy: Content database - */ + // Multi-tenancy - content database if (!c->ContentDbHost.empty()) { if (!content_db.Connect( c->ContentDbHost.c_str(), @@ -154,6 +154,11 @@ bool WorldBoot::LoadDatabaseConnections() } else { content_db.SetMySQL(database); + // 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 + // when database actions are occurring in different threads + database.SetMutex(mutex); + content_db.SetMutex(mutex); } return true; @@ -652,3 +657,8 @@ void WorldBoot::CheckForPossibleConfigurationIssues() } } +void WorldBoot::Shutdown() +{ + safe_delete(mutex); +} + diff --git a/world/world_boot.h b/world/world_boot.h index 9e6f9b6552..19af9bba75 100644 --- a/world/world_boot.h +++ b/world/world_boot.h @@ -15,6 +15,7 @@ class WorldBoot { static void RegisterLoginservers(); static bool DatabaseLoadRoutines(int argc, char **argv); static void CheckForPossibleConfigurationIssues(); + static void Shutdown(); }; diff --git a/world/world_server_cli.cpp b/world/world_server_cli.cpp index 787c3b90e6..13adb11b5a 100644 --- a/world/world_server_cli.cpp +++ b/world/world_server_cli.cpp @@ -31,10 +31,12 @@ void WorldserverCLI::CommandHandler(int argc, char **argv) function_map["test:expansion"] = &WorldserverCLI::ExpansionTestCommand; function_map["test:repository"] = &WorldserverCLI::TestRepository; function_map["test:repository2"] = &WorldserverCLI::TestRepository2; + function_map["test:db-concurrency"] = &WorldserverCLI::TestDatabaseConcurrency; EQEmuCommand::HandleMenu(function_map, cmd, argc, argv); } +#include "cli/database_concurrency.cpp" #include "cli/copy_character.cpp" #include "cli/database_dump.cpp" #include "cli/database_get_schema.cpp" diff --git a/world/world_server_cli.h b/world/world_server_cli.h index 954c36cd19..4255522390 100644 --- a/world/world_server_cli.h +++ b/world/world_server_cli.h @@ -18,6 +18,7 @@ class WorldserverCLI { static void ExpansionTestCommand(int argc, char **argv, argh::parser &cmd, std::string &description); static void TestRepository(int argc, char **argv, argh::parser &cmd, std::string &description); static void TestRepository2(int argc, char **argv, argh::parser &cmd, std::string &description); + static void TestDatabaseConcurrency(int argc, char **argv, argh::parser &cmd, std::string &description); }; diff --git a/zone/main.cpp b/zone/main.cpp index d004ea2313..19d6823205 100644 --- a/zone/main.cpp +++ b/zone/main.cpp @@ -231,6 +231,8 @@ int main(int argc, char** argv) { worldserver.SetLauncherName("NONE"); } + auto mutex = new Mutex; + LogInfo("Connecting to MySQL"); if (!database.Connect( Config->DatabaseHost.c_str(), @@ -242,9 +244,7 @@ int main(int argc, char** argv) { return 1; } - /** - * Multi-tenancy: Content Database - */ + // Multi-tenancy: Content Database if (!Config->ContentDbHost.empty()) { if (!content_db.Connect( Config->ContentDbHost.c_str() , @@ -259,6 +259,11 @@ int main(int argc, char** argv) { } } else { content_db.SetMySQL(database); + // 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 + // when database actions are occurring in different threads + database.SetMutex(mutex); + content_db.SetMutex(mutex); } /* Register Log System and Settings */ @@ -613,6 +618,9 @@ int main(int argc, char** argv) { safe_delete(parse); LogInfo("Proper zone shutdown complete."); LogSys.CloseFileLogs(); + + safe_delete(mutex); + return 0; } From 3b5fda5e07f1fb01d14f805b91de60f6ebb4335f Mon Sep 17 00:00:00 2001 From: Akkadius Date: Fri, 24 Feb 2023 18:04:13 -0600 Subject: [PATCH 4/5] Post rebase --- common/dbcore.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/dbcore.cpp b/common/dbcore.cpp index 02917d2db6..79b89a8dae 100644 --- a/common/dbcore.cpp +++ b/common/dbcore.cpp @@ -294,7 +294,7 @@ std::string DBcore::Escape(const std::string& s) { const std::size_t s_len = s.length(); std::vector temp((s_len * 2) + 1, '\0'); - mysql_real_escape_string(&mysql, temp.data(), s.c_str(), s_len); + mysql_real_escape_string(mysql, temp.data(), s.c_str(), s_len); return temp.data(); } From 1297c0916541f19c399763eee7defe250d0494ab Mon Sep 17 00:00:00 2001 From: Akkadius Date: Fri, 24 Feb 2023 18:05:10 -0600 Subject: [PATCH 5/5] Formatting --- common/dbcore.cpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/common/dbcore.cpp b/common/dbcore.cpp index 79b89a8dae..9b9108f0c0 100644 --- a/common/dbcore.cpp +++ b/common/dbcore.cpp @@ -34,16 +34,16 @@ DBcore::DBcore() { - mysql = mysql_init(nullptr); - mysqlOwner = true; - pHost = nullptr; - pUser = nullptr; - pPassword = nullptr; - pDatabase = nullptr; - pCompress = false; - pSSL = false; - pStatus = Closed; - m_mutex = new Mutex; + mysql = mysql_init(nullptr); + mysqlOwner = true; + pHost = nullptr; + pUser = nullptr; + pPassword = nullptr; + pDatabase = nullptr; + pCompress = false; + pSSL = false; + pStatus = Closed; + m_mutex = new Mutex; } DBcore::~DBcore()