aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMachiavelli <none@none>2010-08-18 02:25:52 +0200
committerMachiavelli <none@none>2010-08-18 02:25:52 +0200
commit87218eadcdeac5ba86a035edfd079958405cb24f (patch)
treeb72020ed0d390953b70d2026bf4c0b16c8271d11 /src
parent1ab2bd6d58adf35090ca3a9ef82eee00a14ff507 (diff)
* HIGHLY EXPERIMENTAL - USE AT OWN RISK *
Database Layer: - Implement connection pooling: Instead of 1 delay thread per database, you can configure between 1 and 32 worker threads that have a seperate thread in the core and have a seperate connection to the MySQL server (based on raczman/Albator´s database layer for Trinitycore3) - Implement a configurable thread bundle for synchroneous requests from seperate core threads (see worldserver.conf.dist for more info) - Every mapupdate thread now has its seperate MySQL connection to the world and characters database - Drop inconsistent PExecuteLog function - query logging will be implemented CONSISTENTLY later - Drop current prepared statement interface - this will be done *properly* later - You´ll need to update your worldserver.conf and authserver.conf - You´re recommended to make a backup of your databases before using this. * HIGHLY EXPERIMENTAL - USE AT OWN RISK * * HIGHLY EXPERIMENTAL - USE AT OWN RISK * etc. --HG-- branch : trunk
Diffstat (limited to 'src')
-rw-r--r--src/server/authserver/Main.cpp22
-rw-r--r--src/server/authserver/authserver.conf.dist38
-rw-r--r--src/server/game/Accounts/AccountMgr.cpp23
-rw-r--r--src/server/game/Chat/Channels/Channel.cpp16
-rw-r--r--src/server/game/Chat/Commands/Level2.cpp52
-rw-r--r--src/server/game/Entities/Creature/Creature.cpp12
-rw-r--r--src/server/game/Entities/GameObject/GameObject.cpp8
-rw-r--r--src/server/game/Entities/Player/Player.cpp4
-rw-r--r--src/server/game/Entities/Player/Player.h2
-rw-r--r--src/server/game/Globals/ObjectMgr.cpp11
-rw-r--r--src/server/game/Maps/MapUpdater.cpp6
-rw-r--r--src/server/game/Server/Protocol/Handlers/CharacterHandler.cpp6
-rw-r--r--src/server/game/Server/Protocol/Handlers/MiscHandler.cpp2
-rw-r--r--src/server/game/Server/Protocol/Handlers/QueryHandler.cpp2
-rw-r--r--src/server/game/Server/WorldSocketMgr.cpp25
-rw-r--r--src/server/game/Tools/PlayerDump.cpp3
-rw-r--r--src/server/game/World/World.cpp9
-rw-r--r--src/server/game/World/World.h7
-rw-r--r--src/server/shared/Database/AsyncDatabaseImpl.h250
-rw-r--r--src/server/shared/Database/DatabaseEnv.h8
-rw-r--r--src/server/shared/Database/DatabaseImpl.h234
-rw-r--r--src/server/shared/Database/DatabaseWorker.cpp67
-rw-r--r--src/server/shared/Database/DatabaseWorker.h42
-rw-r--r--src/server/shared/Database/DatabaseWorkerPool.cpp216
-rw-r--r--src/server/shared/Database/DatabaseWorkerPool.h157
-rw-r--r--src/server/shared/Database/MySQLConnection.cpp244
-rw-r--r--src/server/shared/Database/MySQLConnection.h56
-rw-r--r--src/server/shared/Database/MySQLThreading.h53
-rw-r--r--src/server/shared/Database/PreparedStatements.cpp93
-rw-r--r--src/server/shared/Database/PreparedStatements.h30
-rw-r--r--src/server/shared/Database/SQLOperation.cpp (renamed from src/server/shared/Database/SqlOperations.cpp)149
-rw-r--r--src/server/shared/Database/SQLOperation.h122
-rw-r--r--src/server/shared/Database/SQLStorage.cpp2
-rw-r--r--src/server/shared/Database/SqlOperations.h168
-rw-r--r--src/server/shared/PrecompiledHeaders/sharedPCH.h4
-rw-r--r--src/server/worldserver/CommandLine/CliRunnable.cpp36
-rw-r--r--src/server/worldserver/Master.cpp47
-rw-r--r--src/server/worldserver/WorldThread/WorldRunnable.cpp37
-rw-r--r--src/server/worldserver/worldserver.conf.dist30
39 files changed, 1565 insertions, 728 deletions
diff --git a/src/server/authserver/Main.cpp b/src/server/authserver/Main.cpp
index 88a98cd6cdb..849e1f71248 100644
--- a/src/server/authserver/Main.cpp
+++ b/src/server/authserver/Main.cpp
@@ -24,7 +24,6 @@
#include "Common.h"
#include "Database/DatabaseEnv.h"
-#include "Database/PreparedStatements.h"
#include "Configuration/Config.h"
#include "Log.h"
@@ -315,7 +314,7 @@ extern int main(int argc, char **argv)
{
loopCounter = 0;
sLog.outDetail("Ping MySQL to keep connection alive");
- sPreparedStatement.Query(&LoginDatabase, "auth_ping");
+ LoginDatabase.Query("SELECT 1 FROM realmlist");
}
#ifdef _WIN32
if (m_ServiceStatus == 0) stopEvent = true;
@@ -323,9 +322,8 @@ extern int main(int argc, char **argv)
#endif
}
- ///- Wait for the delay thread to exit
- LoginDatabase.ThreadEnd();
- LoginDatabase.HaltDelayThread();
+ ///- Close the Database Pool
+ LoginDatabase.Close();
sLog.outString("Halting process...");
return 0;
@@ -341,16 +339,18 @@ bool StartDB()
return false;
}
- if (!LoginDatabase.Initialize(dbstring.c_str()))
+ uint8 num_threads = sConfig.GetIntDefault("LoginDatabase.WorkerThreads", 1);
+ if (num_threads < 1 || num_threads > 32)
+ {
+ sLog.outError("Improper value specified for LoginDatabase.WorkerThreads, defaulting to 1.");
+ num_threads = 1;
+ }
+
+ if (!LoginDatabase.Open(dbstring.c_str(), num_threads))
{
sLog.outError("Cannot connect to database");
return false;
}
- LoginDatabase.ThreadStart();
-
- uint32 count = 0;
- sPreparedStatement.LoadAuthserver(&LoginDatabase, count);
- sLog.outString("Loaded %u prepared MySQL statements for auth DB.", count);
return true;
}
diff --git a/src/server/authserver/authserver.conf.dist b/src/server/authserver/authserver.conf.dist
index 0ecb58bf14b..56788381af8 100644
--- a/src/server/authserver/authserver.conf.dist
+++ b/src/server/authserver/authserver.conf.dist
@@ -7,17 +7,6 @@
###############################################################################
# AUTH SERVER SETTINGS
#
-# LoginDatabaseInfo
-# Database connection settings for the realm server.
-# Default:
-# hostname;port;username;password;database
-# .;somenumber;username;password;database
-# - use named pipes in Windows
-# Named pipes: mySQL required adding
-# "enable-named-pipe" to [mysqld] section my.ini
-# .;/path/to/unix_socket;username;password;database
-# - use Unix sockets in Unix/Linux
-#
# LogsDir
# Logs directory setting.
# Important: Logs dir must exists, or all logs need to be disabled
@@ -146,3 +135,30 @@ RealmsStateUpdateDelay = 20
WrongPass.MaxCount = 0
WrongPass.BanTime = 600
WrongPass.BanType = 0
+
+###############################################################################
+# MYSQL SETTINGS
+#
+# LoginDatabaseInfo
+# Database connection settings for the realm server.
+# Default:
+# hostname;port;username;password;database
+# .;somenumber;username;password;database
+# - use named pipes in Windows
+# Named pipes: mySQL required adding
+# "enable-named-pipe" to [mysqld] section my.ini
+# .;/path/to/unix_socket;username;password;database
+# - use Unix sockets in Unix/Linux
+#
+# LoginDatabase.WorkerThreads
+# The amount of worker threads spawned to handle
+# asynchroneous MySQL statements
+# Each worker thread is mirrored with its own
+# connection to the MySQL server and their own
+# thread on the MySQL server.
+# Default: 1
+#
+###############################################################################
+
+LoginDatabaseInfo = "127.0.0.1;3306;trinity;trinity;auth"
+LoginDatabase.WorkerThreads = 1
diff --git a/src/server/game/Accounts/AccountMgr.cpp b/src/server/game/Accounts/AccountMgr.cpp
index 4c641fa9d87..8a53daa8278 100644
--- a/src/server/game/Accounts/AccountMgr.cpp
+++ b/src/server/game/Accounts/AccountMgr.cpp
@@ -48,8 +48,7 @@ AccountOpResult AccountMgr::CreateAccount(std::string username, std::string pass
return AOR_NAME_ALREDY_EXIST; // username does already exist
}
- if (!LoginDatabase.PExecute("INSERT INTO account(username,sha_pass_hash,joindate) VALUES('%s','%s',NOW())", username.c_str(), CalculateShaPassHash(username, password).c_str()))
- return AOR_DB_INTERNAL_ERROR; // unexpected error
+ LoginDatabase.PExecute("INSERT INTO account(username,sha_pass_hash,joindate) VALUES('%s','%s',NOW())", username.c_str(), CalculateShaPassHash(username, password).c_str());
LoginDatabase.Execute("INSERT INTO realmcharacters (realmid, acctid, numchars) SELECT realmlist.id, account.id, 0 FROM realmlist,account LEFT JOIN realmcharacters ON acctid=account.id WHERE acctid IS NULL");
return AOR_OK; // everything's fine
@@ -89,16 +88,12 @@ AccountOpResult AccountMgr::DeleteAccount(uint32 accid)
LoginDatabase.BeginTransaction();
- bool res =
- LoginDatabase.PExecute("DELETE FROM account WHERE id='%d'", accid) &&
- LoginDatabase.PExecute("DELETE FROM account_access WHERE id ='%d'", accid) &&
- LoginDatabase.PExecute("DELETE FROM realmcharacters WHERE acctid='%d'", accid);
+ LoginDatabase.PExecute("DELETE FROM account WHERE id='%d'", accid);
+ LoginDatabase.PExecute("DELETE FROM account_access WHERE id ='%d'", accid);
+ LoginDatabase.PExecute("DELETE FROM realmcharacters WHERE acctid='%d'", accid);
LoginDatabase.CommitTransaction();
- if (!res)
- return AOR_DB_INTERNAL_ERROR; // unexpected error;
-
return AOR_OK;
}
@@ -120,9 +115,8 @@ AccountOpResult AccountMgr::ChangeUsername(uint32 accid, std::string new_uname,
std::string safe_new_uname = new_uname;
LoginDatabase.escape_string(safe_new_uname);
- if (!LoginDatabase.PExecute("UPDATE account SET v='0',s='0',username='%s',sha_pass_hash='%s' WHERE id='%d'", safe_new_uname.c_str(),
- CalculateShaPassHash(new_uname, new_passwd).c_str(), accid))
- return AOR_DB_INTERNAL_ERROR; // unexpected error
+ LoginDatabase.PExecute("UPDATE account SET v='0',s='0',username='%s',sha_pass_hash='%s' WHERE id='%d'", safe_new_uname.c_str(),
+ CalculateShaPassHash(new_uname, new_passwd).c_str(), accid);
return AOR_OK;
}
@@ -141,9 +135,8 @@ AccountOpResult AccountMgr::ChangePassword(uint32 accid, std::string new_passwd)
normalizeString(new_passwd);
// also reset s and v to force update at next realmd login
- if (!LoginDatabase.PExecute("UPDATE account SET v='0', s='0', sha_pass_hash='%s' WHERE id='%d'",
- CalculateShaPassHash(username, new_passwd).c_str(), accid))
- return AOR_DB_INTERNAL_ERROR; // unexpected error
+ LoginDatabase.PExecute("UPDATE account SET v='0', s='0', sha_pass_hash='%s' WHERE id='%d'",
+ CalculateShaPassHash(username, new_passwd).c_str(), accid);
return AOR_OK;
}
diff --git a/src/server/game/Chat/Channels/Channel.cpp b/src/server/game/Chat/Channels/Channel.cpp
index d1001db5ccb..91b7944a4f5 100644
--- a/src/server/game/Chat/Channels/Channel.cpp
+++ b/src/server/game/Chat/Channels/Channel.cpp
@@ -84,12 +84,10 @@ Channel::Channel(const std::string& name, uint32 channel_id, uint32 Team)
else // save
{
// _name is already escaped at this point.
- if (CharacterDatabase.PExecute("INSERT INTO channels (m_name, m_team, m_announce, m_moderate, m_public, m_password) "
- "VALUES ('%s', '%u', '1', '0', '1', '')", _name.c_str(), m_Team))
- {
- sLog.outDebug("New Channel(%s) saved", name.c_str());
- m_IsSaved = true;
- }
+ CharacterDatabase.PExecute("INSERT INTO channels (m_name, m_team, m_announce, m_moderate, m_public, m_password) "
+ "VALUES ('%s', '%u', '1', '0', '1', '')", _name.c_str(), m_Team);
+ sLog.outDebug("New Channel(%s) saved", name.c_str());
+ m_IsSaved = true;
}
}
}
@@ -101,8 +99,9 @@ bool Channel::_UpdateStringInDB(const std::string& colName, const std::string& c
std::string _colValue(colValue);
CharacterDatabase.escape_string(_colValue);
CharacterDatabase.escape_string(_name);
- return CharacterDatabase.PExecute("UPDATE channels SET %s = '%s' WHERE m_name = '%s' AND m_team = '%u'",
+ CharacterDatabase.PExecute("UPDATE channels SET %s = '%s' WHERE m_name = '%s' AND m_team = '%u'",
colName.c_str(), _colValue.c_str(), _name.c_str(), m_Team);
+ return true;
}
bool Channel::_UpdateIntInDB(const std::string& colName, int colValue) const
@@ -110,8 +109,9 @@ bool Channel::_UpdateIntInDB(const std::string& colName, int colValue) const
// Prevent SQL-injection
std::string _name(m_name);
CharacterDatabase.escape_string(_name);
- return CharacterDatabase.PExecute("UPDATE channels SET %s = '%u' WHERE m_name = '%s' AND m_team = '%u'",
+ CharacterDatabase.PExecute("UPDATE channels SET %s = '%u' WHERE m_name = '%s' AND m_team = '%u'",
colName.c_str(), colValue, _name.c_str(), m_Team);
+ return true;
}
void Channel::_UpdateBanListInDB() const
diff --git a/src/server/game/Chat/Commands/Level2.cpp b/src/server/game/Chat/Commands/Level2.cpp
index cdbdcfb2051..f81c3322916 100644
--- a/src/server/game/Chat/Commands/Level2.cpp
+++ b/src/server/game/Chat/Commands/Level2.cpp
@@ -1174,7 +1174,7 @@ bool ChatHandler::HandleNpcAddMoveCommand(const char* args)
//WaypointMgr.AddLastNode(lowguid, player->GetPositionX(), player->GetPositionY(), player->GetPositionZ(), player->GetOrientation(), wait, 0);
// update movement type
- WorldDatabase.PExecuteLog("UPDATE creature SET MovementType = '%u' WHERE guid = '%u'", WAYPOINT_MOTION_TYPE,lowguid);
+ WorldDatabase.PExecute("UPDATE creature SET MovementType = '%u' WHERE guid = '%u'", WAYPOINT_MOTION_TYPE,lowguid);
if (pCreature && pCreature->GetWaypointPath())
{
pCreature->SetDefaultMovementType(WAYPOINT_MOTION_TYPE);
@@ -1253,7 +1253,7 @@ bool ChatHandler::HandleNpcFlagCommand(const char* args)
pCreature->SetUInt32Value(UNIT_NPC_FLAGS, npcFlags);
- WorldDatabase.PExecuteLog("UPDATE creature_template SET npcflag = '%u' WHERE entry = '%u'", npcFlags, pCreature->GetEntry());
+ WorldDatabase.PExecute("UPDATE creature_template SET npcflag = '%u' WHERE entry = '%u'", npcFlags, pCreature->GetEntry());
SendSysMessage(LANG_VALUE_SAVED_REJOIN);
@@ -1372,7 +1372,7 @@ bool ChatHandler::HandleNpcMoveCommand(const char* args)
}
}
- WorldDatabase.PExecuteLog("UPDATE creature SET position_x = '%f', position_y = '%f', position_z = '%f', orientation = '%f' WHERE guid = '%u'", x, y, z, o, lowguid);
+ WorldDatabase.PExecute("UPDATE creature SET position_x = '%f', position_y = '%f', position_z = '%f', orientation = '%f' WHERE guid = '%u'", x, y, z, o, lowguid);
PSendSysMessage(LANG_COMMAND_CREATUREMOVED);
return true;
}
@@ -1583,7 +1583,7 @@ bool ChatHandler::HandleNpcFactionIdCommand(const char* args)
}
// and DB
- WorldDatabase.PExecuteLog("UPDATE creature_template SET faction_A = '%u', faction_H = '%u' WHERE entry = '%u'", factionId, factionId, pCreature->GetEntry());
+ WorldDatabase.PExecute("UPDATE creature_template SET faction_A = '%u', faction_H = '%u' WHERE entry = '%u'", factionId, factionId, pCreature->GetEntry());
return true;
}
@@ -1621,7 +1621,7 @@ bool ChatHandler::HandleNpcSpawnDistCommand(const char* args)
pCreature->Respawn();
}
- WorldDatabase.PExecuteLog("UPDATE creature SET spawndist=%f, MovementType=%i WHERE guid=%u",option,mtype,u_guidlow);
+ WorldDatabase.PExecute("UPDATE creature SET spawndist=%f, MovementType=%i WHERE guid=%u",option,mtype,u_guidlow);
PSendSysMessage(LANG_COMMAND_SPAWNDIST,option);
return true;
}
@@ -1653,7 +1653,7 @@ bool ChatHandler::HandleNpcSpawnTimeCommand(const char* args)
else
return false;
- WorldDatabase.PExecuteLog("UPDATE creature SET spawntimesecs=%i WHERE guid=%u",i_stime,u_guidlow);
+ WorldDatabase.PExecute("UPDATE creature SET spawntimesecs=%i WHERE guid=%u",i_stime,u_guidlow);
pCreature->SetRespawnDelay((uint32)i_stime);
PSendSysMessage(LANG_COMMAND_SPAWNTIME,i_stime);
@@ -2384,7 +2384,7 @@ bool ChatHandler::HandleWpAddCommand(const char* args)
Player* player = m_session->GetPlayer();
//Map *map = player->GetMap();
- WorldDatabase.PExecuteLog("INSERT INTO waypoint_data (id, point, position_x, position_y, position_z) VALUES ('%u','%u','%f', '%f', '%f')",
+ WorldDatabase.PExecute("INSERT INTO waypoint_data (id, point, position_x, position_y, position_z) VALUES ('%u','%u','%f', '%f', '%f')",
pathid, point+1, player->GetPositionX(), player->GetPositionY(), player->GetPositionZ());
PSendSysMessage("%s%s%u%s%u%s|r", "|cff00ff00", "PathID: |r|cff00ffff", pathid, "|r|cff00ff00: Waypoint |r|cff00ffff", point+1,"|r|cff00ff00 created. ");
@@ -2588,7 +2588,7 @@ bool ChatHandler::HandleWpEventCommand(const char* args)
if (result)
{
- WorldDatabase.PExecuteLog("DELETE FROM waypoint_scripts WHERE guid = %u", id);
+ WorldDatabase.PExecute("DELETE FROM waypoint_scripts WHERE guid = %u", id);
PSendSysMessage("%s%s%u|r","|cff00ff00","Wp Event: Waypoint script removed: ", id);
}
else
@@ -2647,7 +2647,7 @@ bool ChatHandler::HandleWpEventCommand(const char* args)
{
uint32 newid = atoi(arg_3);
PSendSysMessage("%s%s|r|cff00ffff%u|r|cff00ff00%s|r|cff00ffff%u|r","|cff00ff00","Wp Event: Wypoint scipt guid: ", newid," id changed: ", id);
- WorldDatabase.PExecuteLog("UPDATE waypoint_scripts SET id='%u' WHERE guid='%u'",
+ WorldDatabase.PExecute("UPDATE waypoint_scripts SET id='%u' WHERE guid='%u'",
newid, id); return true;
}
else
@@ -2663,7 +2663,7 @@ bool ChatHandler::HandleWpEventCommand(const char* args)
if (arg_str_2 == "posx")
{
coord = atof(arg_3);
- WorldDatabase.PExecuteLog("UPDATE waypoint_scripts SET x='%f' WHERE guid='%u'",
+ WorldDatabase.PExecute("UPDATE waypoint_scripts SET x='%f' WHERE guid='%u'",
coord, id);
PSendSysMessage("|cff00ff00Waypoint script:|r|cff00ffff %u|r|cff00ff00 position_x updated.|r", id);
return true;
@@ -2671,7 +2671,7 @@ bool ChatHandler::HandleWpEventCommand(const char* args)
else if (arg_str_2 == "posy")
{
coord = atof(arg_3);
- WorldDatabase.PExecuteLog("UPDATE waypoint_scripts SET y='%f' WHERE guid='%u'",
+ WorldDatabase.PExecute("UPDATE waypoint_scripts SET y='%f' WHERE guid='%u'",
coord, id);
PSendSysMessage("|cff00ff00Waypoint script: %u position_y updated.|r", id);
return true;
@@ -2679,7 +2679,7 @@ bool ChatHandler::HandleWpEventCommand(const char* args)
else if (arg_str_2 == "posz")
{
coord = atof(arg_3);
- WorldDatabase.PExecuteLog("UPDATE waypoint_scripts SET z='%f' WHERE guid='%u'",
+ WorldDatabase.PExecute("UPDATE waypoint_scripts SET z='%f' WHERE guid='%u'",
coord, id);
PSendSysMessage("|cff00ff00Waypoint script: |r|cff00ffff%u|r|cff00ff00 position_z updated.|r", id);
return true;
@@ -2687,14 +2687,14 @@ bool ChatHandler::HandleWpEventCommand(const char* args)
else if (arg_str_2 == "orientation")
{
coord = atof(arg_3);
- WorldDatabase.PExecuteLog("UPDATE waypoint_scripts SET o='%f' WHERE guid='%u'",
+ WorldDatabase.PExecute("UPDATE waypoint_scripts SET o='%f' WHERE guid='%u'",
coord, id);
PSendSysMessage("|cff00ff00Waypoint script: |r|cff00ffff%u|r|cff00ff00 orientation updated.|r", id);
return true;
}
else if (arg_str_2 == "dataint")
{
- WorldDatabase.PExecuteLog("UPDATE waypoint_scripts SET %s='%u' WHERE guid='%u'",
+ WorldDatabase.PExecute("UPDATE waypoint_scripts SET %s='%u' WHERE guid='%u'",
arg_2, atoi(arg_3), id);
PSendSysMessage("|cff00ff00Waypoint script: |r|cff00ffff%u|r|cff00ff00 dataint updated.|r", id);
return true;
@@ -2703,7 +2703,7 @@ bool ChatHandler::HandleWpEventCommand(const char* args)
{
std::string arg_str_3 = arg_3;
WorldDatabase.escape_string(arg_str_3);
- WorldDatabase.PExecuteLog("UPDATE waypoint_scripts SET %s='%s' WHERE guid='%u'",
+ WorldDatabase.PExecute("UPDATE waypoint_scripts SET %s='%s' WHERE guid='%u'",
arg_2, arg_str_3.c_str(), id);
}
}
@@ -2832,9 +2832,9 @@ bool ChatHandler::HandleWpModifyCommand(const char* args)
wpCreature->AddObjectToRemoveList();
}
- WorldDatabase.PExecuteLog("DELETE FROM waypoint_data WHERE id='%u' AND point='%u'",
+ WorldDatabase.PExecute("DELETE FROM waypoint_data WHERE id='%u' AND point='%u'",
pathid, point);
- WorldDatabase.PExecuteLog("UPDATE waypoint_data SET point=point-1 WHERE id='%u' AND point>'%u'",
+ WorldDatabase.PExecute("UPDATE waypoint_data SET point=point-1 WHERE id='%u' AND point>'%u'",
pathid, point);
PSendSysMessage(LANG_WAYPOINT_REMOVED);
@@ -2875,7 +2875,7 @@ bool ChatHandler::HandleWpModifyCommand(const char* args)
//sMapMgr.GetMap(npcCreature->GetMapId())->Add(wpCreature2);
}
- WorldDatabase.PExecuteLog("UPDATE waypoint_data SET position_x = '%f',position_y = '%f',position_z = '%f' where id = '%u' AND point='%u'",
+ WorldDatabase.PExecute("UPDATE waypoint_data SET position_x = '%f',position_y = '%f',position_z = '%f' where id = '%u' AND point='%u'",
chr->GetPositionX(), chr->GetPositionY(), chr->GetPositionZ(), pathid, point);
PSendSysMessage(LANG_WAYPOINT_CHANGED);
@@ -2888,7 +2888,7 @@ bool ChatHandler::HandleWpModifyCommand(const char* args)
if (text == 0)
{
// show_str check for present in list of correct values, no sql injection possible
- WorldDatabase.PExecuteLog("UPDATE waypoint_data SET %s=NULL WHERE id='%u' AND point='%u'",
+ WorldDatabase.PExecute("UPDATE waypoint_data SET %s=NULL WHERE id='%u' AND point='%u'",
show_str, pathid, point);
}
else
@@ -2896,7 +2896,7 @@ bool ChatHandler::HandleWpModifyCommand(const char* args)
// show_str check for present in list of correct values, no sql injection possible
std::string text2 = text;
WorldDatabase.escape_string(text2);
- WorldDatabase.PExecuteLog("UPDATE waypoint_data SET %s='%s' WHERE id='%u' AND point='%u'",
+ WorldDatabase.PExecute("UPDATE waypoint_data SET %s='%s' WHERE id='%u' AND point='%u'",
show_str, text2.c_str(), pathid, point);
}
@@ -3031,7 +3031,7 @@ bool ChatHandler::HandleWpShowCommand(const char* args)
{
PSendSysMessage(LANG_WAYPOINT_NOTREMOVED, wpguid);
hasError = true;
- WorldDatabase.PExecuteLog("DELETE FROM creature WHERE guid = '%u'", wpguid);
+ WorldDatabase.PExecute("DELETE FROM creature WHERE guid = '%u'", wpguid);
}
else
{
@@ -3075,7 +3075,7 @@ bool ChatHandler::HandleWpShowCommand(const char* args)
sLog.outDebug("DEBUG: UPDATE waypoint_data SET wpguid = '%u");
// set "wpguid" column to the visual waypoint
- WorldDatabase.PExecuteLog("UPDATE waypoint_data SET wpguid = '%u' WHERE id = '%u' and point = '%u'", wpCreature->GetGUIDLow(), pathid, point);
+ WorldDatabase.PExecute("UPDATE waypoint_data SET wpguid = '%u' WHERE id = '%u' and point = '%u'", wpCreature->GetGUIDLow(), pathid, point);
wpCreature->SaveToDB(map->GetId(), (1 << map->GetSpawnMode()), chr->GetPhaseMaskForSpawn());
// To call _LoadGoods(); _LoadQuests(); CreateTrainerSpells();
@@ -3205,7 +3205,7 @@ bool ChatHandler::HandleWpShowCommand(const char* args)
{
PSendSysMessage(LANG_WAYPOINT_NOTREMOVED, guid);
hasError = true;
- WorldDatabase.PExecuteLog("DELETE FROM creature WHERE guid = '%u'", guid);
+ WorldDatabase.PExecute("DELETE FROM creature WHERE guid = '%u'", guid);
}
else
{
@@ -3216,8 +3216,8 @@ bool ChatHandler::HandleWpShowCommand(const char* args)
}
while (result->NextRow());
// set "wpguid" column to "empty" - no visual waypoint spawned
- WorldDatabase.PExecuteLog("UPDATE waypoint_data SET wpguid = '0'");
- //WorldDatabase.PExecuteLog("UPDATE creature_movement SET wpguid = '0' WHERE wpguid <> '0'");
+ WorldDatabase.PExecute("UPDATE waypoint_data SET wpguid = '0'");
+ //WorldDatabase.PExecute("UPDATE creature_movement SET wpguid = '0' WHERE wpguid <> '0'");
if (hasError)
{
@@ -4210,7 +4210,7 @@ bool ChatHandler::HandleNpcAddFormationCommand(const char* args)
CreatureGroupMap[lowguid] = group_member;
pCreature->SearchFormation();
- WorldDatabase.PExecuteLog("INSERT INTO creature_formations (leaderGUID, memberGUID, dist, angle, groupAI) VALUES ('%u','%u','%f', '%f', '%u')",
+ WorldDatabase.PExecute("INSERT INTO creature_formations (leaderGUID, memberGUID, dist, angle, groupAI) VALUES ('%u','%u','%f', '%f', '%u')",
leaderGUID, lowguid, group_member->follow_dist, group_member->follow_angle, group_member->groupAI);
PSendSysMessage("Creature %u added to formation with leader %u", lowguid, leaderGUID);
diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp
index bf1b77edc36..f64cdb57e5f 100644
--- a/src/server/game/Entities/Creature/Creature.cpp
+++ b/src/server/game/Entities/Creature/Creature.cpp
@@ -1054,7 +1054,7 @@ void Creature::SaveToDB(uint32 mapid, uint8 spawnMask, uint32 phaseMask)
// updated in DB
WorldDatabase.BeginTransaction();
- WorldDatabase.PExecuteLog("DELETE FROM creature WHERE guid = '%u'", m_DBTableGuid);
+ WorldDatabase.PExecute("DELETE FROM creature WHERE guid = '%u'", m_DBTableGuid);
std::ostringstream ss;
ss << "INSERT INTO creature VALUES ("
@@ -1077,7 +1077,7 @@ void Creature::SaveToDB(uint32 mapid, uint8 spawnMask, uint32 phaseMask)
<< (m_isDeadByDefault ? 1 : 0) << "," //is_dead
<< GetDefaultMovementType() << ")"; //default movement generator type
- WorldDatabase.PExecuteLog(ss.str().c_str());
+ WorldDatabase.PExecute(ss.str().c_str());
WorldDatabase.CommitTransaction();
}
@@ -1349,10 +1349,10 @@ void Creature::DeleteFromDB()
sObjectMgr.DeleteCreatureData(m_DBTableGuid);
WorldDatabase.BeginTransaction();
- WorldDatabase.PExecuteLog("DELETE FROM creature WHERE guid = '%u'", m_DBTableGuid);
- WorldDatabase.PExecuteLog("DELETE FROM creature_addon WHERE guid = '%u'", m_DBTableGuid);
- WorldDatabase.PExecuteLog("DELETE FROM game_event_creature WHERE guid = '%u'", m_DBTableGuid);
- WorldDatabase.PExecuteLog("DELETE FROM game_event_model_equip WHERE guid = '%u'", m_DBTableGuid);
+ WorldDatabase.PExecute("DELETE FROM creature WHERE guid = '%u'", m_DBTableGuid);
+ WorldDatabase.PExecute("DELETE FROM creature_addon WHERE guid = '%u'", m_DBTableGuid);
+ WorldDatabase.PExecute("DELETE FROM game_event_creature WHERE guid = '%u'", m_DBTableGuid);
+ WorldDatabase.PExecute("DELETE FROM game_event_model_equip WHERE guid = '%u'", m_DBTableGuid);
WorldDatabase.CommitTransaction();
}
diff --git a/src/server/game/Entities/GameObject/GameObject.cpp b/src/server/game/Entities/GameObject/GameObject.cpp
index c89f2b866e3..89f17450a83 100644
--- a/src/server/game/Entities/GameObject/GameObject.cpp
+++ b/src/server/game/Entities/GameObject/GameObject.cpp
@@ -645,8 +645,8 @@ void GameObject::SaveToDB(uint32 mapid, uint8 spawnMask, uint32 phaseMask)
<< uint32(GetGoState()) << ")";
WorldDatabase.BeginTransaction();
- WorldDatabase.PExecuteLog("DELETE FROM gameobject WHERE guid = '%u'", m_DBTableGuid);
- WorldDatabase.PExecuteLog(ss.str().c_str());
+ WorldDatabase.PExecute("DELETE FROM gameobject WHERE guid = '%u'", m_DBTableGuid);
+ WorldDatabase.PExecute(ss.str().c_str());
WorldDatabase.CommitTransaction();
}
@@ -722,8 +722,8 @@ void GameObject::DeleteFromDB()
{
sObjectMgr.SaveGORespawnTime(m_DBTableGuid,GetInstanceId(),0);
sObjectMgr.DeleteGOData(m_DBTableGuid);
- WorldDatabase.PExecuteLog("DELETE FROM gameobject WHERE guid = '%u'", m_DBTableGuid);
- WorldDatabase.PExecuteLog("DELETE FROM game_event_gameobject WHERE guid = '%u'", m_DBTableGuid);
+ WorldDatabase.PExecute("DELETE FROM gameobject WHERE guid = '%u'", m_DBTableGuid);
+ WorldDatabase.PExecute("DELETE FROM game_event_gameobject WHERE guid = '%u'", m_DBTableGuid);
}
GameObject* GameObject::GetGameObject(WorldObject& object, uint64 guid)
diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp
index 9a78bafeba9..ade749671e8 100644
--- a/src/server/game/Entities/Player/Player.cpp
+++ b/src/server/game/Entities/Player/Player.cpp
@@ -59,7 +59,7 @@
#include "OutdoorPvPMgr.h"
#include "ArenaTeam.h"
#include "Chat.h"
-#include "DatabaseImpl.h"
+#include "AsyncDatabaseImpl.h"
#include "Spell.h"
#include "SocialMgr.h"
#include "GameEventMgr.h"
@@ -15811,7 +15811,7 @@ float Player::GetFloatValueFromArray(Tokens const& data, uint16 index)
return result;
}
-bool Player::LoadFromDB(uint32 guid, SqlQueryHolder *holder)
+bool Player::LoadFromDB(uint32 guid, SQLQueryHolder *holder)
{
//// 0 1 2 3 4 5 6 7 8 9 10 11
//QueryResult *result = CharacterDatabase.PQuery("SELECT guid, account,name, race, class, gender, level, xp, money, playerBytes, playerBytes2, playerFlags,"
diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h
index 65cc4783ff7..002e1314365 100644
--- a/src/server/game/Entities/Player/Player.h
+++ b/src/server/game/Entities/Player/Player.h
@@ -1407,7 +1407,7 @@ class Player : public Unit, public GridObject<Player>
/*** LOAD SYSTEM ***/
/*********************************************************/
- bool LoadFromDB(uint32 guid, SqlQueryHolder *holder);
+ bool LoadFromDB(uint32 guid, SQLQueryHolder *holder);
bool isBeingLoaded() const { return GetSession()->PlayerLoading();}
void Initialize(uint32 guid);
diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp
index 6c434219a1e..d83f7447f4c 100644
--- a/src/server/game/Globals/ObjectMgr.cpp
+++ b/src/server/game/Globals/ObjectMgr.cpp
@@ -5822,7 +5822,7 @@ bool ObjectMgr::AddGraveYardLink(uint32 id, uint32 zoneId, uint32 team, bool inD
// add link to DB
if (inDB)
{
- WorldDatabase.PExecuteLog("INSERT INTO game_graveyard_zone (id,ghost_zone,faction) "
+ WorldDatabase.PExecute("INSERT INTO game_graveyard_zone (id,ghost_zone,faction) "
"VALUES ('%u', '%u','%u')",id,zoneId,team);
}
@@ -8033,8 +8033,9 @@ bool ObjectMgr::AddGameTele(GameTele& tele)
m_GameTeleMap[new_id] = tele;
- return WorldDatabase.PExecuteLog("INSERT INTO game_tele (id,position_x,position_y,position_z,orientation,map,name) VALUES (%u,%f,%f,%f,%f,%d,'%s')",
+ WorldDatabase.PExecute("INSERT INTO game_tele (id,position_x,position_y,position_z,orientation,map,name) VALUES (%u,%f,%f,%f,%f,%d,'%s')",
new_id,tele.position_x,tele.position_y,tele.position_z,tele.orientation,tele.mapId,tele.name.c_str());
+ return true;
}
bool ObjectMgr::DeleteGameTele(const std::string& name)
@@ -8051,7 +8052,7 @@ bool ObjectMgr::DeleteGameTele(const std::string& name)
{
if (itr->second.wnameLow == wname)
{
- WorldDatabase.PExecuteLog("DELETE FROM game_tele WHERE name = '%s'",itr->second.name.c_str());
+ WorldDatabase.PExecute("DELETE FROM game_tele WHERE name = '%s'",itr->second.name.c_str());
m_GameTeleMap.erase(itr);
return true;
}
@@ -8577,7 +8578,7 @@ void ObjectMgr::AddVendorItem(uint32 entry,uint32 item, int32 maxcount, uint32 i
vList.AddItem(item, maxcount, incrtime, extendedcost);
if (savetodb)
- WorldDatabase.PExecuteLog("INSERT INTO npc_vendor (entry,item,maxcount,incrtime,extendedcost) VALUES('%u','%u','%u','%u','%u')", entry, item, maxcount, incrtime, extendedcost);
+ WorldDatabase.PExecute("INSERT INTO npc_vendor (entry,item,maxcount,incrtime,extendedcost) VALUES('%u','%u','%u','%u','%u')", entry, item, maxcount, incrtime, extendedcost);
}
bool ObjectMgr::RemoveVendorItem(uint32 entry,uint32 item, bool savetodb)
@@ -8589,7 +8590,7 @@ bool ObjectMgr::RemoveVendorItem(uint32 entry,uint32 item, bool savetodb)
if(!iter->second.RemoveItem(item))
return false;
- if (savetodb) WorldDatabase.PExecuteLog("DELETE FROM npc_vendor WHERE entry='%u' AND item='%u'",entry, item);
+ if (savetodb) WorldDatabase.PExecute("DELETE FROM npc_vendor WHERE entry='%u' AND item='%u'",entry, item);
return true;
}
diff --git a/src/server/game/Maps/MapUpdater.cpp b/src/server/game/Maps/MapUpdater.cpp
index 5720ed1eb50..7e1b82f2275 100644
--- a/src/server/game/Maps/MapUpdater.cpp
+++ b/src/server/game/Maps/MapUpdater.cpp
@@ -16,7 +16,8 @@ class WDBThreadStartReq1 : public ACE_Method_Request
virtual int call()
{
- WorldDatabase.ThreadStart();
+ WorldDatabase.Init_MySQL_Connection();
+ CharacterDatabase.Init_MySQL_Connection();
return 0;
}
};
@@ -31,7 +32,8 @@ class WDBThreadEndReq1 : public ACE_Method_Request
virtual int call()
{
- WorldDatabase.ThreadEnd();
+ WorldDatabase.End_MySQL_Connection();
+ CharacterDatabase.End_MySQL_Connection();
return 0;
}
};
diff --git a/src/server/game/Server/Protocol/Handlers/CharacterHandler.cpp b/src/server/game/Server/Protocol/Handlers/CharacterHandler.cpp
index f25dd5824dc..2a764a366e8 100644
--- a/src/server/game/Server/Protocol/Handlers/CharacterHandler.cpp
+++ b/src/server/game/Server/Protocol/Handlers/CharacterHandler.cpp
@@ -27,7 +27,7 @@
#include "WorldSession.h"
#include "MD5.h"
#include "DatabaseEnv.h"
-#include "DatabaseImpl.h"
+#include "AsyncDatabaseImpl.h"
#include "ArenaTeam.h"
#include "Chat.h"
@@ -44,7 +44,7 @@
#include "Util.h"
#include "ScriptMgr.h"
-class LoginQueryHolder : public SqlQueryHolder
+class LoginQueryHolder : public SQLQueryHolder
{
private:
uint32 m_accountId;
@@ -117,7 +117,7 @@ class CharacterHandler
return;
session->HandleCharEnum(result);
}
- void HandlePlayerLoginCallback(QueryResult_AutoPtr /*dummy*/, SqlQueryHolder * holder)
+ void HandlePlayerLoginCallback(QueryResult_AutoPtr /*dummy*/, SQLQueryHolder * holder)
{
if (!holder) return;
WorldSession *session = sWorld.FindSession(((LoginQueryHolder*)holder)->GetAccountId());
diff --git a/src/server/game/Server/Protocol/Handlers/MiscHandler.cpp b/src/server/game/Server/Protocol/Handlers/MiscHandler.cpp
index 2656478f899..79e3374c975 100644
--- a/src/server/game/Server/Protocol/Handlers/MiscHandler.cpp
+++ b/src/server/game/Server/Protocol/Handlers/MiscHandler.cpp
@@ -21,7 +21,7 @@
#include "Common.h"
#include "Language.h"
#include "DatabaseEnv.h"
-#include "DatabaseImpl.h"
+#include "AsyncDatabaseImpl.h"
#include "WorldPacket.h"
#include "Opcodes.h"
#include "Log.h"
diff --git a/src/server/game/Server/Protocol/Handlers/QueryHandler.cpp b/src/server/game/Server/Protocol/Handlers/QueryHandler.cpp
index 0aa6ded77f0..7cb60435d69 100644
--- a/src/server/game/Server/Protocol/Handlers/QueryHandler.cpp
+++ b/src/server/game/Server/Protocol/Handlers/QueryHandler.cpp
@@ -21,7 +21,7 @@
#include "Common.h"
#include "Language.h"
#include "DatabaseEnv.h"
-#include "DatabaseImpl.h"
+#include "AsyncDatabaseImpl.h"
#include "WorldPacket.h"
#include "WorldSession.h"
#include "Opcodes.h"
diff --git a/src/server/game/Server/WorldSocketMgr.cpp b/src/server/game/Server/WorldSocketMgr.cpp
index 9a50456919f..1293849c496 100644
--- a/src/server/game/Server/WorldSocketMgr.cpp
+++ b/src/server/game/Server/WorldSocketMgr.cpp
@@ -158,7 +158,21 @@ class ReactorRunnable : protected ACE_Task_Base
{
DEBUG_LOG ("Network Thread Starting");
- WorldDatabase.ThreadStart();
+ bool needInit = true;
+ if (!(sWorld.getConfig(CONFIG_MYSQL_BUNDLE_LOGINDB) & MYSQL_BUNDLE_RA))
+ {
+ LoginDatabase.Init_MySQL_Connection();
+ needInit = false;
+ }
+
+ if (!(sWorld.getConfig(CONFIG_MYSQL_BUNDLE_CHARDB) & MYSQL_BUNDLE_RA))
+ {
+ CharacterDatabase.Init_MySQL_Connection();
+ needInit = false;
+ }
+
+ if (needInit)
+ MySQL::Thread_Init();
ACE_ASSERT (m_Reactor);
@@ -195,7 +209,14 @@ class ReactorRunnable : protected ACE_Task_Base
}
}
- WorldDatabase.ThreadEnd();
+ ///- Free MySQL thread resources and deallocate lingering connections
+ if (!(sWorld.getConfig(CONFIG_MYSQL_BUNDLE_LOGINDB) & MYSQL_BUNDLE_RA))
+ LoginDatabase.End_MySQL_Connection();
+ if (!(sWorld.getConfig(CONFIG_MYSQL_BUNDLE_CHARDB) & MYSQL_BUNDLE_RA))
+ CharacterDatabase.End_MySQL_Connection();
+
+ if (needInit)
+ MySQL::Thread_End();
DEBUG_LOG ("Network Thread Exitting");
diff --git a/src/server/game/Tools/PlayerDump.cpp b/src/server/game/Tools/PlayerDump.cpp
index 402a274f3cf..4fed5faa7dd 100644
--- a/src/server/game/Tools/PlayerDump.cpp
+++ b/src/server/game/Tools/PlayerDump.cpp
@@ -629,8 +629,7 @@ DumpReturn PlayerDumpReader::LoadDump(const std::string& file, uint32 account, s
fixNULLfields(line);
- if (!CharacterDatabase.Execute(line.c_str()))
- ROLLBACK(DUMP_FILE_BROKEN);
+ CharacterDatabase.Execute(line.c_str());
}
CharacterDatabase.CommitTransaction();
diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp
index 0e5bd88fbb8..15794718491 100644
--- a/src/server/game/World/World.cpp
+++ b/src/server/game/World/World.cpp
@@ -54,7 +54,7 @@
#include "VMapFactory.h"
#include "GameEventMgr.h"
#include "PoolMgr.h"
-#include "DatabaseImpl.h"
+#include "AsyncDatabaseImpl.h"
#include "GridNotifiersImpl.h"
#include "CellImpl.h"
#include "InstanceSaveMgr.h"
@@ -1223,6 +1223,11 @@ void World::LoadConfigSettings(bool reload)
// Dungeon finder
m_configs[CONFIG_DUNGEON_FINDER_ENABLE] = sConfig.GetBoolDefault("DungeonFinder.Enable", false);
+ // MySQL thread bundling config for other runnable tasks
+ m_configs[CONFIG_MYSQL_BUNDLE_LOGINDB] = sConfig.GetIntDefault("LoginDatabase.ThreadBundleMask", MYSQL_BUNDLE_ALL);
+ m_configs[CONFIG_MYSQL_BUNDLE_CHARDB] = sConfig.GetIntDefault("CharacterDatabase.ThreadBundleMask", MYSQL_BUNDLE_ALL);
+ m_configs[CONFIG_MYSQL_BUNDLE_WORLDDB] = sConfig.GetIntDefault("WorldDatabase.ThreadBundleMask", MYSQL_BUNDLE_ALL);
+
sScriptMgr.OnConfigLoad(reload);
}
@@ -2478,7 +2483,7 @@ void World::SendRNDBroadcast()
void World::InitResultQueue()
{
- m_resultQueue = new SqlResultQueue;
+ m_resultQueue = new SQLResultQueue;
CharacterDatabase.SetResultQueue(m_resultQueue);
}
diff --git a/src/server/game/World/World.h b/src/server/game/World/World.h
index 817e8253fe8..8a480d0ccc6 100644
--- a/src/server/game/World/World.h
+++ b/src/server/game/World/World.h
@@ -42,7 +42,7 @@ class WorldSession;
class Player;
struct ScriptAction;
struct ScriptInfo;
-class SqlResultQueue;
+class SQLResultQueue;
class QueryResult;
class WorldSocket;
class SystemMgr;
@@ -286,6 +286,9 @@ enum WorldConfigs
CONFIG_CHARDELETE_MIN_LEVEL,
CONFIG_CLEAN_CHARACTER_DB,
CONFIG_DUNGEON_FINDER_ENABLE,
+ CONFIG_MYSQL_BUNDLE_LOGINDB,
+ CONFIG_MYSQL_BUNDLE_CHARDB,
+ CONFIG_MYSQL_BUNDLE_WORLDDB,
CONFIG_VALUE_COUNT
};
@@ -761,7 +764,7 @@ class World
// CLI command holder to be thread safe
ACE_Based::LockedQueue<CliCommandHolder*,ACE_Thread_Mutex> cliCmdQueue;
- SqlResultQueue *m_resultQueue;
+ SQLResultQueue *m_resultQueue;
// next daily quests and random bg reset time
time_t m_NextDailyQuestReset;
diff --git a/src/server/shared/Database/AsyncDatabaseImpl.h b/src/server/shared/Database/AsyncDatabaseImpl.h
new file mode 100644
index 00000000000..f85540a8016
--- /dev/null
+++ b/src/server/shared/Database/AsyncDatabaseImpl.h
@@ -0,0 +1,250 @@
+/*
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
+ *
+ * Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include "Database/DatabaseWorkerPool.h"
+#include "Database/SQLOperation.h"
+
+
+/// Function body definitions for the template function members of the Database class
+
+#define ASYNC_QUERY_BODY(sql, queue_itr) \
+ if (!sql) return false; \
+ \
+ QueryQueues::iterator queue_itr; \
+ \
+ { \
+ ACE_Based::Thread * queryThread = ACE_Based::Thread::current(); \
+ queue_itr = m_queryQueues.find(queryThread); \
+ if (queue_itr == m_queryQueues.end()) return false; \
+ }
+
+#define ASYNC_PQUERY_BODY(format, szQuery) \
+ if(!format) return false; \
+ \
+ char szQuery [MAX_QUERY_LEN]; \
+ \
+ { \
+ va_list ap; \
+ \
+ va_start(ap, format); \
+ int res = vsnprintf( szQuery, MAX_QUERY_LEN, format, ap ); \
+ va_end(ap); \
+ \
+ if(res==-1) \
+ { \
+ sLog.outError("SQL Query truncated (and not execute) for format: %s",format); \
+ return false; \
+ } \
+ }
+
+
+#define ASYNC_DELAYHOLDER_BODY(holder, queue_itr) \
+ if (!holder) return false; \
+ \
+ QueryQueues::iterator queue_itr; \
+ \
+ { \
+ ACE_Based::Thread * queryThread = ACE_Based::Thread::current(); \
+ queue_itr = m_queryQueues.find(queryThread); \
+ if (queue_itr == m_queryQueues.end()) return false; \
+ }
+
+
+// -- Query / member --
+
+
+template<class Class>
+bool
+DatabaseWorkerPool::AsyncQuery(Class *object, void (Class::*method)(QueryResult_AutoPtr), const char *sql)
+{
+ ASYNC_QUERY_BODY(sql, itr)
+ SQLQueryTask* task = new SQLQueryTask(sql, new Trinity::QueryCallback<Class>(object, method), itr->second);
+ Enqueue(task);
+ return true;
+}
+
+
+template<class Class, typename ParamType1>
+bool
+DatabaseWorkerPool::AsyncQuery(Class *object, void (Class::*method)(QueryResult_AutoPtr, ParamType1), ParamType1 param1, const char *sql)
+{
+ ASYNC_QUERY_BODY(sql, itr)
+ SQLQueryTask* task = new SQLQueryTask(sql, new Trinity::QueryCallback<Class, ParamType1>(object, method, (QueryResult_AutoPtr)NULL, param1), itr->second);
+ Enqueue(task);
+ return true;
+}
+
+
+template<class Class, typename ParamType1, typename ParamType2>
+bool
+DatabaseWorkerPool::AsyncQuery(Class *object, void (Class::*method)(QueryResult_AutoPtr, ParamType1, ParamType2), ParamType1 param1, ParamType2 param2, const char *sql)
+{
+ ASYNC_QUERY_BODY(sql, itr)
+ SQLQueryTask* task = new SQLQueryTask(sql, new Trinity::QueryCallback<Class, ParamType1, ParamType2>(object, method, (QueryResult_AutoPtr)NULL, param1, param2), itr->second);
+ Enqueue(task);
+ return true;
+}
+
+
+template<class Class, typename ParamType1, typename ParamType2, typename ParamType3>
+bool
+DatabaseWorkerPool::AsyncQuery(Class *object, void (Class::*method)(QueryResult_AutoPtr, ParamType1, ParamType2, ParamType3), ParamType1 param1, ParamType2 param2, ParamType3 param3, const char *sql)
+{
+ ASYNC_QUERY_BODY(sql, itr)
+ SQLQueryTask* task = new SQLQueryTask(sql, new Trinity::QueryCallback<Class, ParamType1, ParamType2, ParamType3>(object, method, (QueryResult_AutoPtr)NULL, param1, param2, param3), itr->second);
+ Enqueue(task);
+ return true;
+}
+
+
+// -- Query / static --
+
+
+template<typename ParamType1>
+bool
+DatabaseWorkerPool::AsyncQuery(void (*method)(QueryResult_AutoPtr, ParamType1), ParamType1 param1, const char *sql)
+{
+ ASYNC_QUERY_BODY(sql, itr)
+ SQLQueryTask* task = new SQLQueryTask(sql, new Trinity::SQueryCallback<ParamType1>(method, (QueryResult_AutoPtr)NULL, param1), itr->second);
+ Enqueue(task);
+ return true;
+}
+
+
+template<typename ParamType1, typename ParamType2>
+bool
+DatabaseWorkerPool::AsyncQuery(void (*method)(QueryResult_AutoPtr, ParamType1, ParamType2), ParamType1 param1, ParamType2 param2, const char *sql)
+{
+ ASYNC_QUERY_BODY(sql, itr)
+ SQLQueryTask* task = new SQLQueryTask(sql, new Trinity::SQueryCallback<ParamType1, ParamType2>(method, (QueryResult_AutoPtr)NULL, param1, param2), itr->second);
+ Enqueue(task);
+ return true;
+}
+
+
+template<typename ParamType1, typename ParamType2, typename ParamType3>
+bool
+DatabaseWorkerPool::AsyncQuery(void (*method)(QueryResult_AutoPtr, ParamType1, ParamType2, ParamType3), ParamType1 param1, ParamType2 param2, ParamType3 param3, const char *sql)
+{
+ ASYNC_QUERY_BODY(sql, itr)
+ SQLQueryTask* task = new SQLQueryTask(sql, new Trinity::SQueryCallback<ParamType1, ParamType2, ParamType3>(method, (QueryResult_AutoPtr)NULL, param1, param2, param3), itr->second);
+ Enqueue(task);
+ return true;
+}
+
+
+// -- PQuery / member --
+
+
+template<class Class>
+bool
+DatabaseWorkerPool::AsyncPQuery(Class *object, void (Class::*method)(QueryResult_AutoPtr), const char *format,...)
+{
+ ASYNC_PQUERY_BODY(format, szQuery)
+ return AsyncQuery(object, method, szQuery);
+}
+
+
+template<class Class, typename ParamType1>
+bool
+DatabaseWorkerPool::AsyncPQuery(Class *object, void (Class::*method)(QueryResult_AutoPtr, ParamType1), ParamType1 param1, const char *format,...)
+{
+ ASYNC_PQUERY_BODY(format, szQuery)
+ return AsyncQuery(object, method, param1, szQuery);
+}
+
+
+template<class Class, typename ParamType1, typename ParamType2>
+bool
+DatabaseWorkerPool::AsyncPQuery(Class *object, void (Class::*method)(QueryResult_AutoPtr, ParamType1, ParamType2), ParamType1 param1, ParamType2 param2, const char *format,...)
+{
+ ASYNC_PQUERY_BODY(format, szQuery)
+ return AsyncQuery(object, method, param1, param2, szQuery);
+}
+
+
+template<class Class, typename ParamType1, typename ParamType2, typename ParamType3>
+bool
+DatabaseWorkerPool::AsyncPQuery(Class *object, void (Class::*method)(QueryResult_AutoPtr, ParamType1, ParamType2, ParamType3), ParamType1 param1, ParamType2 param2, ParamType3 param3, const char *format,...)
+{
+ ASYNC_PQUERY_BODY(format, szQuery)
+ return AsyncQuery(object, method, param1, param2, param3, szQuery);
+}
+
+
+// -- PQuery / static --
+
+
+template<typename ParamType1>
+bool
+DatabaseWorkerPool::AsyncPQuery(void (*method)(QueryResult_AutoPtr, ParamType1), ParamType1 param1, const char *format,...)
+{
+ ASYNC_PQUERY_BODY(format, szQuery)
+ return AsyncQuery(method, param1, szQuery);
+}
+
+
+template<typename ParamType1, typename ParamType2>
+bool
+DatabaseWorkerPool::AsyncPQuery(void (*method)(QueryResult_AutoPtr, ParamType1, ParamType2), ParamType1 param1, ParamType2 param2, const char *format,...)
+{
+ ASYNC_PQUERY_BODY(format, szQuery)
+ return AsyncQuery(method, param1, param2, szQuery);
+}
+
+
+template<typename ParamType1, typename ParamType2, typename ParamType3>
+bool
+DatabaseWorkerPool::AsyncPQuery(void (*method)(QueryResult_AutoPtr, ParamType1, ParamType2, ParamType3), ParamType1 param1, ParamType2 param2, ParamType3 param3, const char *format,...)
+{
+ ASYNC_PQUERY_BODY(format, szQuery)
+ return AsyncQuery(method, param1, param2, param3, szQuery);
+}
+
+
+// -- QueryHolder --
+
+
+template<class Class>
+bool
+DatabaseWorkerPool::DelayQueryHolder(Class *object, void (Class::*method)(QueryResult_AutoPtr, SQLQueryHolder*), SQLQueryHolder *holder)
+{
+ ASYNC_DELAYHOLDER_BODY(holder, itr)
+ SQLQueryHolderTask *task = new SQLQueryHolderTask(holder, new Trinity::QueryCallback<Class, SQLQueryHolder*>(object, method, (QueryResult_AutoPtr)NULL, holder), itr->second);
+ Enqueue(task);
+ return true;
+}
+
+
+template<class Class, typename ParamType1>
+bool
+DatabaseWorkerPool::DelayQueryHolder(Class *object, void (Class::*method)(QueryResult_AutoPtr, SQLQueryHolder*, ParamType1), SQLQueryHolder *holder, ParamType1 param1)
+{
+ ASYNC_DELAYHOLDER_BODY(holder, itr)
+ SQLQueryHolderTask *task = new SQLQueryHolderTask(holder, new Trinity::QueryCallback<Class, SQLQueryHolder*, ParamType1>(object, method, (QueryResult_AutoPtr)NULL, holder, param1), itr->second);
+ Enqueue(task);
+ return true;
+}
+
+
+#undef ASYNC_QUERY_BODY
+#undef ASYNC_PQUERY_BODY
+#undef ASYNC_DELAYHOLDER_BODY
diff --git a/src/server/shared/Database/DatabaseEnv.h b/src/server/shared/Database/DatabaseEnv.h
index 15c1b1c599e..398ae66f235 100644
--- a/src/server/shared/Database/DatabaseEnv.h
+++ b/src/server/shared/Database/DatabaseEnv.h
@@ -28,8 +28,10 @@
#include "Database/Field.h"
#include "Database/QueryResult.h"
-#include "Database/Database.h"
-typedef Database DatabaseType;
+#include "Database/DatabaseWorkerPool.h"
+#include "Database/MySQLThreading.h"
+
+typedef DatabaseWorkerPool DatabaseType;
#define _LIKE_ "LIKE"
#define _TABLE_SIM_ "`"
#define _CONCAT3_(A,B,C) "CONCAT( " A " , " B " , " C " )"
@@ -39,5 +41,7 @@ extern DatabaseType WorldDatabase;
extern DatabaseType CharacterDatabase;
extern DatabaseType LoginDatabase;
+#define MAX_QUERY_LEN 32*1024
+
#endif
diff --git a/src/server/shared/Database/DatabaseImpl.h b/src/server/shared/Database/DatabaseImpl.h
deleted file mode 100644
index f0ba9c84a30..00000000000
--- a/src/server/shared/Database/DatabaseImpl.h
+++ /dev/null
@@ -1,234 +0,0 @@
-/*
- * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
- *
- * Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-
-#include "Database/Database.h"
-#include "Database/SqlOperations.h"
-
-
-/// Function body definitions for the template function members of the Database class
-
-
-#define ASYNC_QUERY_BODY(sql, queue_itr) \
- if (!sql) return false; \
- \
- QueryQueues::iterator queue_itr; \
- \
- { \
- ACE_Based::Thread * queryThread = ACE_Based::Thread::current(); \
- queue_itr = m_queryQueues.find(queryThread); \
- if (queue_itr == m_queryQueues.end()) return false; \
- }
-
-
-#define ASYNC_PQUERY_BODY(format, szQuery) \
- if(!format) return false; \
- \
- char szQuery [MAX_QUERY_LEN]; \
- \
- { \
- va_list ap; \
- \
- va_start(ap, format); \
- int res = vsnprintf( szQuery, MAX_QUERY_LEN, format, ap ); \
- va_end(ap); \
- \
- if(res==-1) \
- { \
- sLog.outError("SQL Query truncated (and not execute) for format: %s",format); \
- return false; \
- } \
- }
-
-
-#define ASYNC_DELAYHOLDER_BODY(holder, queue_itr) \
- if (!holder) return false; \
- \
- QueryQueues::iterator queue_itr; \
- \
- { \
- ACE_Based::Thread * queryThread = ACE_Based::Thread::current(); \
- queue_itr = m_queryQueues.find(queryThread); \
- if (queue_itr == m_queryQueues.end()) return false; \
- }
-
-
-// -- Query / member --
-
-
-template<class Class>
-bool
-Database::AsyncQuery(Class *object, void (Class::*method)(QueryResult_AutoPtr), const char *sql)
-{
- ASYNC_QUERY_BODY(sql, itr)
- return m_threadBody->Delay(new SqlQuery(sql, new Trinity::QueryCallback<Class>(object, method), itr->second));
-}
-
-
-template<class Class, typename ParamType1>
-bool
-Database::AsyncQuery(Class *object, void (Class::*method)(QueryResult_AutoPtr, ParamType1), ParamType1 param1, const char *sql)
-{
- ASYNC_QUERY_BODY(sql, itr)
- return m_threadBody->Delay(new SqlQuery(sql, new Trinity::QueryCallback<Class, ParamType1>(object, method, (QueryResult_AutoPtr)NULL, param1), itr->second));
-}
-
-
-template<class Class, typename ParamType1, typename ParamType2>
-bool
-Database::AsyncQuery(Class *object, void (Class::*method)(QueryResult_AutoPtr, ParamType1, ParamType2), ParamType1 param1, ParamType2 param2, const char *sql)
-{
- ASYNC_QUERY_BODY(sql, itr)
- return m_threadBody->Delay(new SqlQuery(sql, new Trinity::QueryCallback<Class, ParamType1, ParamType2>(object, method, (QueryResult_AutoPtr)NULL, param1, param2), itr->second));
-}
-
-
-template<class Class, typename ParamType1, typename ParamType2, typename ParamType3>
-bool
-Database::AsyncQuery(Class *object, void (Class::*method)(QueryResult_AutoPtr, ParamType1, ParamType2, ParamType3), ParamType1 param1, ParamType2 param2, ParamType3 param3, const char *sql)
-{
- ASYNC_QUERY_BODY(sql, itr)
- return m_threadBody->Delay(new SqlQuery(sql, new Trinity::QueryCallback<Class, ParamType1, ParamType2, ParamType3>(object, method, (QueryResult_AutoPtr)NULL, param1, param2, param3), itr->second));
-}
-
-
-// -- Query / static --
-
-
-template<typename ParamType1>
-bool
-Database::AsyncQuery(void (*method)(QueryResult_AutoPtr, ParamType1), ParamType1 param1, const char *sql)
-{
- ASYNC_QUERY_BODY(sql, itr)
- return m_threadBody->Delay(new SqlQuery(sql, new Trinity::SQueryCallback<ParamType1>(method, (QueryResult_AutoPtr)NULL, param1), itr->second));
-}
-
-
-template<typename ParamType1, typename ParamType2>
-bool
-Database::AsyncQuery(void (*method)(QueryResult_AutoPtr, ParamType1, ParamType2), ParamType1 param1, ParamType2 param2, const char *sql)
-{
- ASYNC_QUERY_BODY(sql, itr)
- return m_threadBody->Delay(new SqlQuery(sql, new Trinity::SQueryCallback<ParamType1, ParamType2>(method, (QueryResult_AutoPtr)NULL, param1, param2), itr->second));
-}
-
-
-template<typename ParamType1, typename ParamType2, typename ParamType3>
-bool
-Database::AsyncQuery(void (*method)(QueryResult_AutoPtr, ParamType1, ParamType2, ParamType3), ParamType1 param1, ParamType2 param2, ParamType3 param3, const char *sql)
-{
- ASYNC_QUERY_BODY(sql, itr)
- return m_threadBody->Delay(new SqlQuery(sql, new Trinity::SQueryCallback<ParamType1, ParamType2, ParamType3>(method, (QueryResult_AutoPtr)NULL, param1, param2, param3), itr->second));
-}
-
-
-// -- PQuery / member --
-
-
-template<class Class>
-bool
-Database::AsyncPQuery(Class *object, void (Class::*method)(QueryResult_AutoPtr), const char *format,...)
-{
- ASYNC_PQUERY_BODY(format, szQuery)
- return AsyncQuery(object, method, szQuery);
-}
-
-
-template<class Class, typename ParamType1>
-bool
-Database::AsyncPQuery(Class *object, void (Class::*method)(QueryResult_AutoPtr, ParamType1), ParamType1 param1, const char *format,...)
-{
- ASYNC_PQUERY_BODY(format, szQuery)
- return AsyncQuery(object, method, param1, szQuery);
-}
-
-
-template<class Class, typename ParamType1, typename ParamType2>
-bool
-Database::AsyncPQuery(Class *object, void (Class::*method)(QueryResult_AutoPtr, ParamType1, ParamType2), ParamType1 param1, ParamType2 param2, const char *format,...)
-{
- ASYNC_PQUERY_BODY(format, szQuery)
- return AsyncQuery(object, method, param1, param2, szQuery);
-}
-
-
-template<class Class, typename ParamType1, typename ParamType2, typename ParamType3>
-bool
-Database::AsyncPQuery(Class *object, void (Class::*method)(QueryResult_AutoPtr, ParamType1, ParamType2, ParamType3), ParamType1 param1, ParamType2 param2, ParamType3 param3, const char *format,...)
-{
- ASYNC_PQUERY_BODY(format, szQuery)
- return AsyncQuery(object, method, param1, param2, param3, szQuery);
-}
-
-
-// -- PQuery / static --
-
-
-template<typename ParamType1>
-bool
-Database::AsyncPQuery(void (*method)(QueryResult_AutoPtr, ParamType1), ParamType1 param1, const char *format,...)
-{
- ASYNC_PQUERY_BODY(format, szQuery)
- return AsyncQuery(method, param1, szQuery);
-}
-
-
-template<typename ParamType1, typename ParamType2>
-bool
-Database::AsyncPQuery(void (*method)(QueryResult_AutoPtr, ParamType1, ParamType2), ParamType1 param1, ParamType2 param2, const char *format,...)
-{
- ASYNC_PQUERY_BODY(format, szQuery)
- return AsyncQuery(method, param1, param2, szQuery);
-}
-
-
-template<typename ParamType1, typename ParamType2, typename ParamType3>
-bool
-Database::AsyncPQuery(void (*method)(QueryResult_AutoPtr, ParamType1, ParamType2, ParamType3), ParamType1 param1, ParamType2 param2, ParamType3 param3, const char *format,...)
-{
- ASYNC_PQUERY_BODY(format, szQuery)
- return AsyncQuery(method, param1, param2, param3, szQuery);
-}
-
-
-// -- QueryHolder --
-
-
-template<class Class>
-bool
-Database::DelayQueryHolder(Class *object, void (Class::*method)(QueryResult_AutoPtr, SqlQueryHolder*), SqlQueryHolder *holder)
-{
- ASYNC_DELAYHOLDER_BODY(holder, itr)
- return holder->Execute(new Trinity::QueryCallback<Class, SqlQueryHolder*>(object, method, (QueryResult_AutoPtr)NULL, holder), m_threadBody, itr->second);
-}
-
-
-template<class Class, typename ParamType1>
-bool
-Database::DelayQueryHolder(Class *object, void (Class::*method)(QueryResult_AutoPtr, SqlQueryHolder*, ParamType1), SqlQueryHolder *holder, ParamType1 param1)
-{
- ASYNC_DELAYHOLDER_BODY(holder, itr)
- return holder->Execute(new Trinity::QueryCallback<Class, SqlQueryHolder*, ParamType1>(object, method, (QueryResult_AutoPtr)NULL, holder, param1), m_threadBody, itr->second);
-}
-
-
-#undef ASYNC_QUERY_BODY
-#undef ASYNC_PQUERY_BODY
-#undef ASYNC_DELAYHOLDER_BODY
diff --git a/src/server/shared/Database/DatabaseWorker.cpp b/src/server/shared/Database/DatabaseWorker.cpp
new file mode 100644
index 00000000000..17fc1d75a5d
--- /dev/null
+++ b/src/server/shared/Database/DatabaseWorker.cpp
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "DatabaseEnv.h"
+#include "DatabaseWorker.h"
+#include "SQLOperation.h"
+#include "MySQLConnection.h"
+
+DatabaseWorker::DatabaseWorker(ACE_Activation_Queue* new_queue, MySQLConnection* con) :
+m_queue(new_queue),
+m_conn(con)
+{
+ /// Assign thread to task
+ activate();
+}
+
+int DatabaseWorker::svc()
+{
+ if (!m_queue)
+ return -1;
+
+ SQLOperation *request = NULL;
+ while (1)
+ {
+ request = (SQLOperation*)(m_queue->dequeue());
+ if (!request)
+ break;
+
+ request->SetConnection(m_conn);
+ request->call();
+ delete request;
+ }
+
+ delete m_conn;
+ delete this;
+ return 0;
+}
+
+int DatabaseWorker::activate()
+{
+ /* THR_DETACHED:
+ Create an asynchronous thread. The exit status of the thread would not be available to any other threads.
+ The thread resources are reclaimed by the operating system whenever the thread is terminated. */
+
+ /* THR_NEW_LWP:
+ Create an explicit kernel-level thread (as opposed to a user-level thread). */
+
+ ACE_Task_Base::activate(THR_NEW_LWP | THR_DETACHED, 1);
+ return 0; //^ - Spawn one thread to handle this task.
+ // However more of these tasks may be activated
+ // See DatabaseWorkerPool ctor.
+} \ No newline at end of file
diff --git a/src/server/shared/Database/DatabaseWorker.h b/src/server/shared/Database/DatabaseWorker.h
new file mode 100644
index 00000000000..ad5102d28ca
--- /dev/null
+++ b/src/server/shared/Database/DatabaseWorker.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _WORKERTHREAD_H
+#define _WORKERTHREAD_H
+
+#include <ace/Task.h>
+#include <ace/Activation_Queue.h>
+
+class MySQLConnection;
+
+class DatabaseWorker : protected ACE_Task_Base
+{
+ public:
+ DatabaseWorker(ACE_Activation_Queue* new_queue, MySQLConnection* con);
+
+ ///- Inherited from ACE_Task_Base
+ int svc();
+ int activate();
+
+ private:
+ DatabaseWorker() : ACE_Task_Base() {}
+ ACE_Activation_Queue* m_queue;
+ MySQLConnection* m_conn;
+};
+
+#endif \ No newline at end of file
diff --git a/src/server/shared/Database/DatabaseWorkerPool.cpp b/src/server/shared/Database/DatabaseWorkerPool.cpp
new file mode 100644
index 00000000000..532d9cad7df
--- /dev/null
+++ b/src/server/shared/Database/DatabaseWorkerPool.cpp
@@ -0,0 +1,216 @@
+/*
+ * Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "DatabaseWorkerPool.h"
+#include "MySQLConnection.h"
+#include "DatabaseEnv.h"
+#include "SQLOperation.h"
+
+DatabaseWorkerPool::DatabaseWorkerPool() :
+m_queue(new ACE_Activation_Queue(new ACE_Message_Queue<ACE_MT_SYNCH>)),
+m_connections(0)
+{
+ m_infoString = "";
+
+ mysql_library_init(-1, NULL, NULL);
+ WPFatal (mysql_thread_safe(), "Used MySQL library isn't thread-safe.");
+}
+
+DatabaseWorkerPool::~DatabaseWorkerPool()
+{
+}
+
+bool DatabaseWorkerPool::Open(const std::string& infoString, uint8 num_threads)
+{
+ sLog.outDebug("Creating bundled/master MySQL connection.");
+ m_bundle_conn = new MySQLConnection();
+ m_bundle_conn->Open(infoString);
+ ++m_connections;
+
+ m_async_connections.resize(num_threads);
+
+ /// Open the Async pool
+ for (uint8 i = 0; i < num_threads; i++)
+ {
+ m_async_connections[i] = new MySQLConnection(m_queue);
+ m_async_connections[i]->Open(infoString);
+ ++m_connections;
+ sLog.outDebug("Async database thread pool opened. Worker thread count: %u", num_threads);
+ }
+
+ m_infoString = infoString;
+ return true;
+}
+
+void DatabaseWorkerPool::Close()
+{
+ /// Shuts down worker threads for this connection pool.
+ for (uint8 i = 0; i < m_async_connections.size(); i++)
+ Enqueue(NULL);
+
+ //- MySQL::Thread_End() should be called manually from the aborting calling threads
+
+ delete m_bundle_conn;
+ m_bundle_conn = NULL;
+}
+
+/*! This function creates a new MySQL connection for every MapUpdate thread
+ and every unbundled task.
+ */
+void DatabaseWorkerPool::Init_MySQL_Connection()
+{
+ MySQLConnection* conn = new MySQLConnection();
+ conn->Open(m_infoString);
+
+ {
+ ACE_Guard<ACE_Thread_Mutex> guard(m_connectionMap_mtx);
+ m_sync_connections[ACE_Based::Thread::current()] = conn;
+ }
+
+ sLog.outDebug("Core thread with ID ["UI64FMTD"] initializing MySQL connection.",
+ (uint64)ACE_Based::Thread::currentId());
+}
+
+void DatabaseWorkerPool::End_MySQL_Connection()
+{
+ MySQLConnection* conn;
+ {
+ ACE_Guard<ACE_Thread_Mutex> guard(m_connectionMap_mtx);
+ conn = m_sync_connections[ACE_Based::Thread::current()];
+ }
+ delete conn;
+ conn = NULL;
+}
+
+void DatabaseWorkerPool::Execute(const char* sql)
+{
+ if (!sql)
+ return;
+
+ BasicStatementTask* task = new BasicStatementTask(sql);
+ Enqueue(task);
+}
+
+void DatabaseWorkerPool::PExecute(const char* sql, ...)
+{
+ if (!sql)
+ return;
+
+ va_list ap;
+ char szQuery[MAX_QUERY_LEN];
+ va_start(ap, sql);
+ int res = vsnprintf(szQuery, MAX_QUERY_LEN, sql, ap);
+ va_end(ap);
+
+ Execute(szQuery);
+}
+
+void DatabaseWorkerPool::DirectExecute(const char* sql)
+{
+ if (sql)
+ GetConnection()->Execute(sql);
+}
+
+void DatabaseWorkerPool::DirectPExecute(const char* sql, ...)
+{
+ if (!sql)
+ return;
+
+ va_list ap;
+ char szQuery[MAX_QUERY_LEN];
+ va_start(ap, sql);
+ int res = vsnprintf(szQuery, MAX_QUERY_LEN, sql, ap);
+ va_end(ap);
+
+ return DirectExecute(szQuery);
+}
+
+QueryResult_AutoPtr DatabaseWorkerPool::Query(const char* sql)
+{
+ return GetConnection()->Query(sql);
+}
+
+QueryResult_AutoPtr DatabaseWorkerPool::PQuery(const char* sql, ...)
+{
+ if (!sql)
+ return QueryResult_AutoPtr(NULL);
+
+ va_list ap;
+ char szQuery[MAX_QUERY_LEN];
+ va_start(ap, sql);
+ int res = vsnprintf(szQuery, MAX_QUERY_LEN, sql, ap);
+ va_end(ap);
+
+ return Query(szQuery);
+}
+
+void DatabaseWorkerPool::BeginTransaction()
+{
+ ACE_Guard<ACE_Thread_Mutex> guard(m_transQueues_mtx);
+ ACE_Based::Thread* tranThread = ACE_Based::Thread::current(); // owner of this transaction
+ TransactionQueues::iterator itr = m_tranQueues.find(tranThread);
+ if (itr != m_tranQueues.end() && itr->second != NULL)
+ {
+ itr->second->ForcefulDelete();
+ delete itr->second;
+ }
+ m_tranQueues[tranThread] = new TransactionTask();
+ return;
+}
+
+void DatabaseWorkerPool::RollbackTransaction()
+{
+ ACE_Guard<ACE_Thread_Mutex> guard(m_transQueues_mtx);
+ ACE_Based::Thread* tranThread = ACE_Based::Thread::current(); // owner of this transaction
+ TransactionQueues::iterator itr = m_tranQueues.find(tranThread);
+ if (itr != m_tranQueues.end() && itr->second != NULL)
+ {
+ itr->second->ForcefulDelete();
+ delete itr->second;
+ }
+}
+
+void DatabaseWorkerPool::CommitTransaction()
+{
+ ACE_Guard<ACE_Thread_Mutex> guard(m_transQueues_mtx);
+ ACE_Based::Thread* tranThread = ACE_Based::Thread::current(); // owner of this transaction
+ TransactionQueues::iterator itr = m_tranQueues.find(tranThread);
+ if (itr != m_tranQueues.end() && itr->second != NULL)
+ {
+ Enqueue(itr->second);
+ m_tranQueues.erase(itr);
+ }
+}
+
+
+MySQLConnection* DatabaseWorkerPool::GetConnection()
+{
+ MySQLConnection* conn;
+ ConnectionMap::const_iterator itr;
+ {
+ /*! MapUpdate + unbundled threads */
+ ACE_Guard<ACE_Thread_Mutex> guard(m_connectionMap_mtx);
+ itr = m_sync_connections.find(ACE_Based::Thread::current());
+ if (itr != m_sync_connections.end())
+ conn = itr->second;
+ }
+ /*! Bundled threads */
+ conn = m_bundle_conn;
+ ASSERT (conn);
+ return conn;
+} \ No newline at end of file
diff --git a/src/server/shared/Database/DatabaseWorkerPool.h b/src/server/shared/Database/DatabaseWorkerPool.h
new file mode 100644
index 00000000000..d6275e0307f
--- /dev/null
+++ b/src/server/shared/Database/DatabaseWorkerPool.h
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _DATABASEWORKERPOOL_H
+#define _DATABASEWORKERPOOL_H
+
+#include "Common.h"
+#include "Logging/Log.h"
+
+#include <ace/Activation_Queue.h>
+#include <ace/Atomic_Op_T.h>
+#include <ace/Thread_Mutex.h>
+
+#include "SQLOperation.h"
+#include "QueryResult.h"
+#include "MySQLConnection.h"
+
+enum MySQLThreadBundle
+{
+ MYSQL_BUNDLE_NONE = 0x00, //- Each task will run their own MySQL connection
+ MYSQL_BUNDLE_CLI = 0x01, //- Commandline interface thread
+ MYSQL_BUNDLE_RA = 0x02, //- Remote admin thread
+ MYSQL_BUNDLE_RAR = 0x04, //- Reactor runnable thread
+ MYSQL_BUNDLE_WORLD = 0x08, //- WorldRunnable
+ MYSQL_BUNDLE_ALL = MYSQL_BUNDLE_CLI | MYSQL_BUNDLE_RA | MYSQL_BUNDLE_RAR | MYSQL_BUNDLE_WORLD,
+};
+
+class DatabaseWorkerPool
+{
+ public:
+ DatabaseWorkerPool();
+ ~DatabaseWorkerPool();
+
+ bool Open(const std::string& infoString, uint8 num_threads);
+ void Close();
+
+ void Init_MySQL_Connection();
+ void End_MySQL_Connection();
+
+ void Execute(const char* sql);
+ void PExecute(const char* sql, ...);
+ void DirectExecute(const char* sql);
+ void DirectPExecute(const char* sql, ...);
+ QueryResult_AutoPtr Query(const char* sql);
+ QueryResult_AutoPtr PQuery(const char* sql, ...);
+
+ /// Async queries and query holders, implemented in DatabaseImpl.h
+
+ // Query / member
+ template<class Class>
+ bool AsyncQuery(Class *object, void (Class::*method)(QueryResult_AutoPtr), const char *sql);
+ template<class Class, typename ParamType1>
+ bool AsyncQuery(Class *object, void (Class::*method)(QueryResult_AutoPtr, ParamType1), ParamType1 param1, const char *sql);
+ template<class Class, typename ParamType1, typename ParamType2>
+ bool AsyncQuery(Class *object, void (Class::*method)(QueryResult_AutoPtr, ParamType1, ParamType2), ParamType1 param1, ParamType2 param2, const char *sql);
+ template<class Class, typename ParamType1, typename ParamType2, typename ParamType3>
+ bool AsyncQuery(Class *object, void (Class::*method)(QueryResult_AutoPtr, ParamType1, ParamType2, ParamType3), ParamType1 param1, ParamType2 param2, ParamType3 param3, const char *sql);
+ // Query / static
+ template<typename ParamType1>
+ bool AsyncQuery(void (*method)(QueryResult_AutoPtr, ParamType1), ParamType1 param1, const char *sql);
+ template<typename ParamType1, typename ParamType2>
+ bool AsyncQuery(void (*method)(QueryResult_AutoPtr, ParamType1, ParamType2), ParamType1 param1, ParamType2 param2, const char *sql);
+ template<typename ParamType1, typename ParamType2, typename ParamType3>
+ bool AsyncQuery(void (*method)(QueryResult_AutoPtr, ParamType1, ParamType2, ParamType3), ParamType1 param1, ParamType2 param2, ParamType3 param3, const char *sql);
+ // PQuery / member
+ template<class Class>
+ bool AsyncPQuery(Class *object, void (Class::*method)(QueryResult_AutoPtr), const char *format,...) ATTR_PRINTF(4,5);
+ template<class Class, typename ParamType1>
+ bool AsyncPQuery(Class *object, void (Class::*method)(QueryResult_AutoPtr, ParamType1), ParamType1 param1, const char *format,...) ATTR_PRINTF(5,6);
+ template<class Class, typename ParamType1, typename ParamType2>
+ bool AsyncPQuery(Class *object, void (Class::*method)(QueryResult_AutoPtr, ParamType1, ParamType2), ParamType1 param1, ParamType2 param2, const char *format,...) ATTR_PRINTF(6,7);
+ template<class Class, typename ParamType1, typename ParamType2, typename ParamType3>
+ bool AsyncPQuery(Class *object, void (Class::*method)(QueryResult_AutoPtr, ParamType1, ParamType2, ParamType3), ParamType1 param1, ParamType2 param2, ParamType3 param3, const char *format,...) ATTR_PRINTF(7,8);
+ // PQuery / static
+ template<typename ParamType1>
+ bool AsyncPQuery(void (*method)(QueryResult_AutoPtr, ParamType1), ParamType1 param1, const char *format,...) ATTR_PRINTF(4,5);
+ template<typename ParamType1, typename ParamType2>
+ bool AsyncPQuery(void (*method)(QueryResult_AutoPtr, ParamType1, ParamType2), ParamType1 param1, ParamType2 param2, const char *format,...) ATTR_PRINTF(5,6);
+ template<typename ParamType1, typename ParamType2, typename ParamType3>
+ bool AsyncPQuery(void (*method)(QueryResult_AutoPtr, ParamType1, ParamType2, ParamType3), ParamType1 param1, ParamType2 param2, ParamType3 param3, const char *format,...) ATTR_PRINTF(6,7);
+ template<class Class>
+ // QueryHolder
+ bool DelayQueryHolder(Class *object, void (Class::*method)(QueryResult_AutoPtr, SQLQueryHolder*), SQLQueryHolder *holder);
+ template<class Class, typename ParamType1>
+ bool DelayQueryHolder(Class *object, void (Class::*method)(QueryResult_AutoPtr, SQLQueryHolder*, ParamType1), SQLQueryHolder *holder, ParamType1 param1);
+
+ void SetResultQueue(SQLResultQueue * queue)
+ {
+ m_queryQueues[ACE_Based::Thread::current()] = queue;
+ }
+
+ void BeginTransaction();
+ void RollbackTransaction();
+ void CommitTransaction();
+
+ void escape_string(std::string& str)
+ {
+ if (str.empty())
+ return;
+
+ char* buf = new char[str.size()*2+1];
+ escape_string(buf,str.c_str(),str.size());
+ str = buf;
+ delete[] buf;
+ }
+
+ unsigned long escape_string(char *to, const char *from, unsigned long length)
+ {
+ if (!to || !from || !length)
+ return 0;
+ return (mysql_real_escape_string(GetConnection()->GetHandle(), to, from, length));
+ }
+
+ private:
+ void Enqueue(SQLOperation* op)
+ {
+ m_queue->enqueue(op);
+ }
+
+ MySQLConnection* GetConnection();
+
+ private:
+ typedef UNORDERED_MAP<ACE_Based::Thread*, MySQLConnection*> ConnectionMap;
+ typedef UNORDERED_MAP<ACE_Based::Thread*, TransactionTask*> TransactionQueues;
+ typedef UNORDERED_MAP<ACE_Based::Thread*, SQLResultQueue*> QueryQueues;
+ typedef ACE_Atomic_Op<ACE_SYNCH_MUTEX, uint32> AtomicUInt;
+
+ private:
+ ACE_Activation_Queue* m_queue; //! Queue shared by async worker threads.
+ ACE_Thread_Mutex m_queue_mtx; //! For thread safe enqueues of delayed statements.
+ std::vector<MySQLConnection*> m_async_connections;
+ ConnectionMap m_sync_connections; //! Holds a mysql connection+thread per mapUpdate thread and unbundled runnnables.
+ ACE_Thread_Mutex m_connectionMap_mtx; //! For thread safe access to the synchroneous connection map
+ MySQLConnection* m_bundle_conn; //! Bundled connection (see Database.ThreadBundleMask config)
+ AtomicUInt m_connections; //! Counter of MySQL connections;
+ std::string m_infoString; //! Infostring that is passed on to child connections.
+ TransactionQueues m_tranQueues; //! Transaction queues from diff. threads
+ ACE_Thread_Mutex m_transQueues_mtx; //! To guard m_transQueues
+ QueryQueues m_queryQueues; //! Query queues from diff threads
+};
+
+#endif \ No newline at end of file
diff --git a/src/server/shared/Database/MySQLConnection.cpp b/src/server/shared/Database/MySQLConnection.cpp
new file mode 100644
index 00000000000..cd28474c63d
--- /dev/null
+++ b/src/server/shared/Database/MySQLConnection.cpp
@@ -0,0 +1,244 @@
+/*
+ * Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "MySQLConnection.h"
+#include "DatabaseWorker.h"
+#include "Utilities/Util.h"
+#include "Utilities/Timer.h"
+
+MySQLConnection::MySQLConnection() :
+m_Mysql(NULL)
+{
+}
+
+MySQLConnection::MySQLConnection(ACE_Activation_Queue* queue) :
+m_queue(queue),
+m_Mysql(NULL)
+{
+ m_worker = new DatabaseWorker(m_queue, this);
+}
+
+MySQLConnection::~MySQLConnection()
+{
+ delete m_worker;
+}
+
+bool MySQLConnection::Open(const std::string& infoString)
+{
+ MYSQL *mysqlInit;
+ mysqlInit = mysql_init(NULL);
+ if (!mysqlInit)
+ {
+ sLog.outError("Could not initialize Mysql connection");
+ return false;
+ }
+
+ Tokens tokens = StrSplit(infoString, ";");
+
+ Tokens::iterator iter;
+
+ std::string host, port_or_socket, user, password, database;
+ int port;
+ char const* unix_socket;
+
+ iter = tokens.begin();
+
+ if (iter != tokens.end())
+ host = *iter++;
+ if (iter != tokens.end())
+ port_or_socket = *iter++;
+ if (iter != tokens.end())
+ user = *iter++;
+ if (iter != tokens.end())
+ password = *iter++;
+ if (iter != tokens.end())
+ database = *iter++;
+
+ mysql_options(mysqlInit, MYSQL_SET_CHARSET_NAME, "utf8");
+ #ifdef _WIN32
+ if (host==".") // named pipe use option (Windows)
+ {
+ unsigned int opt = MYSQL_PROTOCOL_PIPE;
+ mysql_options(mysqlInit, MYSQL_OPT_PROTOCOL, (char const*)&opt);
+ port = 0;
+ unix_socket = 0;
+ }
+ else // generic case
+ {
+ port = atoi(port_or_socket.c_str());
+ unix_socket = 0;
+ }
+ #else
+ if (host==".") // socket use option (Unix/Linux)
+ {
+ unsigned int opt = MYSQL_PROTOCOL_SOCKET;
+ mysql_options(mysqlInit, MYSQL_OPT_PROTOCOL, (char const*)&opt);
+ host = "localhost";
+ port = 0;
+ unix_socket = port_or_socket.c_str();
+ }
+ else // generic case
+ {
+ port = atoi(port_or_socket.c_str());
+ unix_socket = 0;
+ }
+ #endif
+
+ m_Mysql = mysql_real_connect(mysqlInit, host.c_str(), user.c_str(),
+ password.c_str(), database.c_str(), port, unix_socket, 0);
+
+ if (m_Mysql)
+ {
+ sLog.outDetail("Connected to MySQL database at %s", host.c_str());
+ sLog.outString("MySQL client library: %s", mysql_get_client_info());
+ sLog.outString("MySQL server ver: %s ", mysql_get_server_info( m_Mysql));
+
+ if (!mysql_autocommit(m_Mysql, 1))
+ sLog.outDetail("AUTOCOMMIT SUCCESSFULLY SET TO 1");
+ else
+ sLog.outDetail("AUTOCOMMIT NOT SET TO 1");
+
+ // set connection properties to UTF8 to properly handle locales for different
+ // server configs - core sends data in UTF8, so MySQL must expect UTF8 too
+ Execute("SET NAMES `utf8`");
+ Execute("SET CHARACTER SET `utf8`");
+
+ #if MYSQL_VERSION_ID >= 50003
+ my_bool my_true = (my_bool)1;
+ if (mysql_options(m_Mysql, MYSQL_OPT_RECONNECT, &my_true))
+ sLog.outDetail("Failed to turn on MYSQL_OPT_RECONNECT.");
+ else
+ sLog.outDetail("Successfully turned on MYSQL_OPT_RECONNECT.");
+ #else
+ #warning "Your mySQL client lib version does not support reconnecting after a timeout.\nIf this causes you any trouble we advice you to upgrade your mySQL client libs to at least mySQL 5.0.13 to resolve this problem."
+ #endif
+ return true;
+ }
+ else
+ {
+ sLog.outError("Could not connect to MySQL database at %s: %s\n", host.c_str(), mysql_error(mysqlInit));
+ mysql_close(mysqlInit);
+ return false;
+ }
+}
+
+bool MySQLConnection::Execute(const char* sql)
+{
+ if (!m_Mysql)
+ return false;
+
+ {
+ // guarded block for thread-safe mySQL request
+ ACE_Guard<ACE_Thread_Mutex> query_connection_guard(m_Mutex);
+
+ #ifdef TRINITY_DEBUG
+ uint32 _s = getMSTime();
+ #endif
+ if (mysql_query(m_Mysql, sql))
+ {
+ sLog.outErrorDb("SQL: %s", sql);
+ sLog.outErrorDb("SQL ERROR: %s", mysql_error(m_Mysql));
+ return false;
+ }
+ else
+ {
+ #ifdef TRINITY_DEBUG
+ sLog.outDebug("[%u ms] SQL: %s", getMSTimeDiff(_s, getMSTime()), sql);
+ #endif
+ }
+ }
+
+ return true;
+}
+
+QueryResult_AutoPtr MySQLConnection::Query(const char* sql)
+{
+ if (!sql)
+ return QueryResult_AutoPtr(NULL);
+
+ MYSQL_RES *result = NULL;
+ MYSQL_FIELD *fields = NULL;
+ uint64 rowCount = 0;
+ uint32 fieldCount = 0;
+
+ if (!_Query(sql, &result, &fields, &rowCount, &fieldCount))
+ return QueryResult_AutoPtr(NULL);
+
+ QueryResult *queryResult = new QueryResult(result, fields, rowCount, fieldCount);
+
+ queryResult->NextRow();
+
+ return QueryResult_AutoPtr(queryResult);
+}
+
+bool MySQLConnection::_Query(const char *sql, MYSQL_RES **pResult, MYSQL_FIELD **pFields, uint64* pRowCount, uint32* pFieldCount)
+{
+ if (!m_Mysql)
+ return false;
+
+ {
+ // guarded block for thread-safe mySQL request
+ ACE_Guard<ACE_Thread_Mutex> query_connection_guard(m_Mutex);
+ #ifdef TRINITY_DEBUG
+ uint32 _s = getMSTime();
+ #endif
+ if (mysql_query(m_Mysql, sql))
+ {
+ sLog.outErrorDb("SQL: %s", sql);
+ sLog.outErrorDb("query ERROR: %s", mysql_error(m_Mysql));
+ return false;
+ }
+ else
+ {
+ #ifdef TRINITY_DEBUG
+ sLog.outDebug("[%u ms] SQL: %s", getMSTimeDiff(_s,getMSTime()), sql);
+ #endif
+ }
+
+ *pResult = mysql_store_result(m_Mysql);
+ *pRowCount = mysql_affected_rows(m_Mysql);
+ *pFieldCount = mysql_field_count(m_Mysql);
+ }
+
+ if (!*pResult )
+ return false;
+
+ if (!*pRowCount)
+ {
+ mysql_free_result(*pResult);
+ return false;
+ }
+
+ *pFields = mysql_fetch_fields(*pResult);
+ return true;
+}
+
+void MySQLConnection::BeginTransaction()
+{
+ Execute("START TRANSACTION");
+}
+
+void MySQLConnection::RollbackTransaction()
+{
+ Execute("ROLLBACK");
+}
+
+void MySQLConnection::CommitTransaction()
+{
+ Execute("COMMIT");
+} \ No newline at end of file
diff --git a/src/server/shared/Database/MySQLConnection.h b/src/server/shared/Database/MySQLConnection.h
new file mode 100644
index 00000000000..08ceaa2860c
--- /dev/null
+++ b/src/server/shared/Database/MySQLConnection.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _MYSQLCONNECTION_H
+#define _MYSQLCONNECTION_H
+
+class DatabaseWorker;
+
+class MySQLConnection
+{
+ friend class DatabaseWorkerPool;
+
+ public:
+ MySQLConnection(); //! Constructor for synchroneous connections.
+ MySQLConnection(ACE_Activation_Queue* queue); //! Constructor for asynchroneous connections.
+ ~MySQLConnection();
+
+ bool Open(const std::string& infoString); //! Connection details.
+
+ public:
+ bool Execute(const char* sql);
+ QueryResult_AutoPtr Query(const char* sql);
+ bool _Query(const char *sql, MYSQL_RES **pResult, MYSQL_FIELD **pFields, uint64* pRowCount, uint32* pFieldCount);
+
+ void BeginTransaction();
+ void RollbackTransaction();
+ void CommitTransaction();
+
+ operator bool () const { return m_Mysql != NULL; }
+
+ protected:
+ MYSQL* GetHandle() { return m_Mysql; }
+
+ private:
+ ACE_Activation_Queue* m_queue; //! Queue shared with other asynchroneous connections.
+ DatabaseWorker* m_worker; //! Core worker task.
+ MYSQL * m_Mysql; //! MySQL Handle.
+ ACE_Thread_Mutex m_Mutex;
+};
+
+#endif \ No newline at end of file
diff --git a/src/server/shared/Database/MySQLThreading.h b/src/server/shared/Database/MySQLThreading.h
new file mode 100644
index 00000000000..3c039a4d165
--- /dev/null
+++ b/src/server/shared/Database/MySQLThreading.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _MYSQLTHREADING_H
+#define _MYSQLTHREADING_H
+
+#include "Log.h"
+
+class MySQL
+{
+ public:
+ /*! Create a thread on the MySQL server to mirrior the calling thread,
+ initializes thread-specific variables and allows thread-specific
+ operations without concurrence from other threads.
+ This should only be called if multiple core threads are running
+ on the same MySQL connection. Seperate MySQL connections implicitly
+ create a mirror thread.
+ */
+ static void Thread_Init()
+ {
+ mysql_thread_init();
+ printf("Core thread with ID ["UI64FMTD"] initializing MySQL thread.",
+ (uint64)ACE_Based::Thread::currentId());
+ }
+
+ /*! Shuts down MySQL thread and frees resources, should only be called
+ when we terminate. MySQL threads and connections are not configurable
+ during runtime.
+ */
+ static void Thread_End()
+ {
+ mysql_thread_end();
+ printf("Core thread with ID ["UI64FMTD"] shutting down MySQL thread.",
+ (uint64)ACE_Based::Thread::currentId());
+ }
+};
+
+#endif \ No newline at end of file
diff --git a/src/server/shared/Database/PreparedStatements.cpp b/src/server/shared/Database/PreparedStatements.cpp
deleted file mode 100644
index ec57a0f90e8..00000000000
--- a/src/server/shared/Database/PreparedStatements.cpp
+++ /dev/null
@@ -1,93 +0,0 @@
-#include "PreparedStatements.h"
-
-void PreparedStatementHolder::_prepareStatement(const char* name, const char* sql, Database *db, uint32 &count)
-{
- const char prefix[] = "PREPARE ";
- size_t querySize = 8 + strlen(name) + 6 + strlen(sql) + 2 + 1;
- char* query = new char[querySize];
- strcpy(query, prefix);
- strcat(query, name);
- strcat(query, " FROM ");
- strcat(query, "'");
- strcat(query, sql);
- strcat(query, "'");
-
- DEBUG_LOG("Preparing statement: %s", query);
- db->Execute(query);
-
- delete[] query;
- ++count;
-}
-
-void PreparedStatementHolder::LoadAuthserver(Database *db, uint32 &count)
-{
- _prepareStatement("auth_ping", "SELECT 1 FROM realmlist LIMIT 1", db, count);
-};
-
-void PreparedStatementHolder::Execute(Database *db, const char *name)
-{
- const char prefix[] = "EXECUTE ";
- size_t querySize = 8 + strlen(name) + 1;
- char* query = new char[querySize];
- strcpy(query, prefix);
- strcat(query, name);
-
- DEBUG_LOG("Prepared statement: %s", query);
- db->Execute(query);
- delete[] query;
-}
-
-void PreparedStatementHolder::PExecute(Database *db, const char *name, const char* args)
-{
- // NOTE: if args == NULL, we're crashing here. No need to waste performance on checking;
- // devs must make sure they use PExecute for args and Execute for no args.
-
- const char prefix[] = "EXECUTE ";
- size_t querySize = 8 + strlen(name) + 7 + strlen(args) + 1;
- char* query = new char[querySize];
- strcpy(query, prefix);
- strcat(query, name);
- strcat(query, " USING ");
- strcat(query, args);
-
- DEBUG_LOG("Prepared statement (parsed args): %s", query);
- db->Execute(query);
- delete[] query;
-}
-
-QueryResult_AutoPtr PreparedStatementHolder::Query(Database *db, const char *name)
-{
- QueryResult_AutoPtr _return = QueryResult_AutoPtr(NULL);
-
- const char prefix[] = "EXECUTE ";
- size_t querySize = 8 + strlen(name) + 1;
- char* query = new char[querySize];
- strcpy(query, prefix);
- strcat(query, name);
-
- DEBUG_LOG("Prepared statement with resultset: %s", query);
- _return = db->Query(query);
- delete[] query;
- return _return;
-}
-
-QueryResult_AutoPtr PreparedStatementHolder::PQuery(Database *db, const char *name, const char *args)
-{
- // NOTE: if args == NULL, we're crashing here. No need to waste performance on checking;
- // devs must make sure they use PQuery for args and Query for no args.
-
- QueryResult_AutoPtr _return = QueryResult_AutoPtr(NULL);
-
- const char prefix[] = "EXECUTE ";
- size_t querySize = 8 + strlen(name) + 7 + strlen(args) + 1;
- char* query = new char[querySize];
- strcpy(query, prefix);
- strcat(query, name);
- strcat(query, " USING ");
- strcat(query, args);
-
- DEBUG_LOG("Prepared statement with resultset (parsed args): %s", query);
- _return = db->Query(query);
- delete[] query;
- return _return;
-} \ No newline at end of file
diff --git a/src/server/shared/Database/PreparedStatements.h b/src/server/shared/Database/PreparedStatements.h
deleted file mode 100644
index 277d2b833ec..00000000000
--- a/src/server/shared/Database/PreparedStatements.h
+++ /dev/null
@@ -1,30 +0,0 @@
-#ifndef sPreparedStatement
-
-#include "ace/Singleton.h"
-#include "Database/DatabaseEnv.h"
-
-class PreparedStatementHolder
-{
- public:
- ///- Load prepare statements on database $db and increase $count for every statement
- void LoadCharacters(Database *db, uint32 &count);
- void LoadAuthserver(Database *db, uint32 &count);
- void LoadWorldserver(Database *db, uint32 &count);
-
- ///- Executes prepared statement that doesn't require feedback with name $name on database $db
- void Execute(Database *db, const char* name);
- ///- Executes prepared statement that doesn't require feedback with name $name and args $args
- ///- on database $db
- void PExecute(Database *db, const char* name, const char* args);
-
- ///- Executes a prepared statement without args on db $db with name $name and puts the result set in a pointer.
- QueryResult_AutoPtr Query(Database* db, const char* name);
- ///- Executes a prepared statement with args $args on db $db with name $name and put the result set in a pointer.
- QueryResult_AutoPtr PQuery(Database* db, const char* name, const char* args);
-
- private:
- void _prepareStatement(const char* name, const char* sql, Database *db, uint32 &count);
-
-};
-#define sPreparedStatement (*ACE_Singleton<PreparedStatementHolder, ACE_Null_Mutex>::instance())
-#endif \ No newline at end of file
diff --git a/src/server/shared/Database/SqlOperations.cpp b/src/server/shared/Database/SQLOperation.cpp
index 33b96a30533..d3af5949faf 100644
--- a/src/server/shared/Database/SqlOperations.cpp
+++ b/src/server/shared/Database/SQLOperation.cpp
@@ -1,6 +1,4 @@
/*
- * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
- *
* Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
@@ -18,71 +16,74 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "SqlOperations.h"
-#include "SqlDelayThread.h"
-#include "DatabaseEnv.h"
-#include "DatabaseImpl.h"
+#include "SQLOperation.h"
+#include "MySQLConnection.h"
-/// ---- ASYNC STATEMENTS / TRANSACTIONS ----
+/*! Basic, ad-hoc queries. */
+BasicStatementTask::BasicStatementTask(const char* sql)
+{
+ m_sql = strdup(sql);
+}
-void SqlStatement::Execute(Database *db)
+BasicStatementTask::~BasicStatementTask()
{
- /// just do it
- db->DirectExecute(m_sql);
+ free((void*)m_sql);
}
-void SqlTransaction::Execute(Database *db)
+bool BasicStatementTask::Execute()
{
- const char* sql;
+ return m_conn->Execute(m_sql);
+}
+
+/*! Transactions. */
+TransactionTask::TransactionTask()
+{
+}
+
+TransactionTask::~TransactionTask()
+{
+
+}
- m_Mutex.acquire();
- if (m_queue.empty())
+void TransactionTask::ForcefulDelete()
+{
+ while (!m_queries.empty())
{
- m_Mutex.release();
- return;
+ free((void*)const_cast<char*>(m_queries.front()));
+ m_queries.pop();
}
+}
- db->DirectExecute("START TRANSACTION");
- while (!m_queue.empty())
- {
- sql = m_queue.front();
+bool TransactionTask::Execute()
+{
+ if (m_queries.empty())
+ return false;
+
+ const char* sql;
- if (!db->DirectExecute(sql))
+ m_conn->BeginTransaction();
+ while (!m_queries.empty())
+ {
+ sql = m_queries.front();
+ if (!m_conn->Execute(sql))
{
free((void*)const_cast<char*>(sql));
- m_queue.pop();
- db->DirectExecute("ROLLBACK");
- while (!m_queue.empty())
- {
- free((void*)const_cast<char*>(m_queue.front()));
- m_queue.pop();
- }
- m_Mutex.release();
- return;
+ m_queries.pop();
+ m_conn->RollbackTransaction();
+ ForcefulDelete();
+ return false;
}
free((void*)const_cast<char*>(sql));
- m_queue.pop();
+ m_queries.pop();
}
- db->DirectExecute("COMMIT");
- m_Mutex.release();
-}
-
-/// ---- ASYNC QUERIES ----
-
-void SqlQuery::Execute(Database *db)
-{
- if (!m_callback || !m_queue)
- return;
-
- /// execute the query and store the result in the callback
- m_callback->SetResult(db->Query(m_sql));
- /// add the callback to the sql result queue of the thread it originated from
- m_queue->add(m_callback);
+ m_conn->CommitTransaction();
+ return true;
}
-void SqlResultQueue::Update()
+/*! Callback statements/holders */
+void SQLResultQueue::Update()
{
/// execute the callbacks waiting in the synchronization queue
Trinity::IQueryCallback* callback;
@@ -93,39 +94,27 @@ void SqlResultQueue::Update()
}
}
-bool SqlQueryHolder::Execute(Trinity::IQueryCallback * callback, SqlDelayThread *thread, SqlResultQueue *queue)
-{
- if (!callback || !thread || !queue)
- return false;
-
- /// delay the execution of the queries, sync them with the delay thread
- /// which will in turn resync on execution (via the queue) and call back
- SqlQueryHolderEx *holderEx = new SqlQueryHolderEx(this, callback, queue);
- thread->Delay(holderEx);
- return true;
-}
-
-bool SqlQueryHolder::SetQuery(size_t index, const char *sql)
+bool SQLQueryHolder::SetQuery(size_t index, const char *sql)
{
if (m_queries.size() <= index)
{
- sLog.outError("Query index (%u) out of range (size: %u) for query: %s",index,(uint32)m_queries.size(),sql);
+ sLog.outError("Query index (%u) out of range (size: %u) for query: %s", index, (uint32)m_queries.size(), sql);
return false;
}
if (m_queries[index].first != NULL)
{
sLog.outError("Attempt assign query to holder index (%u) where other query stored (Old: [%s] New: [%s])",
- index,m_queries[index].first,sql);
+ index, m_queries[index].first, sql);
return false;
}
/// not executed yet, just stored (it's not called a holder for nothing)
- m_queries[index] = SqlResultPair(strdup(sql), QueryResult_AutoPtr(NULL));
+ m_queries[index] = SQLResultPair(strdup(sql), QueryResult_AutoPtr(NULL));
return true;
}
-bool SqlQueryHolder::SetPQuery(size_t index, const char *format, ...)
+bool SQLQueryHolder::SetPQuery(size_t index, const char *format, ...)
{
if (!format)
{
@@ -145,10 +134,10 @@ bool SqlQueryHolder::SetPQuery(size_t index, const char *format, ...)
return false;
}
- return SetQuery(index,szQuery);
+ return SetQuery(index, szQuery);
}
-QueryResult_AutoPtr SqlQueryHolder::GetResult(size_t index)
+QueryResult_AutoPtr SQLQueryHolder::GetResult(size_t index)
{
if (index < m_queries.size())
{
@@ -165,14 +154,14 @@ QueryResult_AutoPtr SqlQueryHolder::GetResult(size_t index)
return QueryResult_AutoPtr(NULL);
}
-void SqlQueryHolder::SetResult(size_t index, QueryResult_AutoPtr result)
+void SQLQueryHolder::SetResult(size_t index, QueryResult_AutoPtr result)
{
/// store the result in the holder
if (index < m_queries.size())
m_queries[index].second = result;
}
-SqlQueryHolder::~SqlQueryHolder()
+SQLQueryHolder::~SQLQueryHolder()
{
for (size_t i = 0; i < m_queries.size(); i++)
{
@@ -183,27 +172,41 @@ SqlQueryHolder::~SqlQueryHolder()
}
}
-void SqlQueryHolder::SetSize(size_t size)
+void SQLQueryHolder::SetSize(size_t size)
{
/// to optimize push_back, reserve the number of queries about to be executed
m_queries.resize(size);
}
-void SqlQueryHolderEx::Execute(Database *db)
+bool SQLQueryHolderTask::Execute()
{
if (!m_holder || !m_callback || !m_queue)
- return;
+ return false;
/// we can do this, we are friends
- std::vector<SqlQueryHolder::SqlResultPair> &queries = m_holder->m_queries;
+ std::vector<SQLQueryHolder::SQLResultPair> &queries = m_holder->m_queries;
for (size_t i = 0; i < queries.size(); i++)
{
/// execute all queries in the holder and pass the results
char const *sql = queries[i].first;
- if(sql) m_holder->SetResult(i, db->Query(sql));
+ if (sql)
+ m_holder->SetResult(i, m_conn->Query(sql));
}
/// sync with the caller thread
m_queue->add(m_callback);
+ return true;
}
+
+bool SQLQueryTask::Execute()
+{
+ if (!m_callback || !m_queue)
+ return false;
+
+ /// execute the query and store the result in the callback
+ m_callback->SetResult(m_conn->Query(m_sql));
+ /// add the callback to the sql result queue of the thread it originated from
+ m_queue->add(m_callback);
+ return true;
+} \ No newline at end of file
diff --git a/src/server/shared/Database/SQLOperation.h b/src/server/shared/Database/SQLOperation.h
new file mode 100644
index 00000000000..8f2a59151a3
--- /dev/null
+++ b/src/server/shared/Database/SQLOperation.h
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _SQLOPERATION_H
+#define _SQLOPERATION_H
+
+#include <ace/Method_Request.h>
+
+#include "Common.h"
+#include "Threading/Callback.h"
+
+class MySQLConnection;
+
+class SQLOperation : public ACE_Method_Request
+{
+ public:
+ SQLOperation(){};
+ int call()
+ {
+ Execute();
+ return 0;
+ }
+ virtual bool Execute() = 0;
+
+ virtual void SetConnection(MySQLConnection* con) { m_conn = con; }
+
+ MySQLConnection* m_conn;
+};
+
+/*! Raw, ad-hoc query. */
+class BasicStatementTask : public SQLOperation
+{
+ public:
+ BasicStatementTask(const char* sql);
+ ~BasicStatementTask();
+
+ bool Execute();
+
+ private:
+ const char* m_sql; //- Raw query to be executed
+};
+
+/*! Transactions */
+class TransactionTask : public SQLOperation
+{
+ public:
+ TransactionTask();
+ ~TransactionTask();
+ void ForcefulDelete();
+
+ bool Execute();
+
+ private:
+ std::queue<char*> m_queries;
+};
+
+/*! ResultQueue */
+class SQLResultQueue : public ACE_Based::LockedQueue<Trinity::IQueryCallback* , ACE_Thread_Mutex>
+{
+ public:
+ SQLResultQueue() {}
+ void Update();
+};
+
+class SQLQueryHolder
+{
+ friend class SQLQueryHolderTask;
+ private:
+ typedef std::pair<const char*, QueryResult_AutoPtr> SQLResultPair;
+ std::vector<SQLResultPair> m_queries;
+ public:
+ SQLQueryHolder() {}
+ ~SQLQueryHolder();
+ bool SetQuery(size_t index, const char *sql);
+ bool SetPQuery(size_t index, const char *format, ...) ATTR_PRINTF(3,4);
+ void SetSize(size_t size);
+ QueryResult_AutoPtr GetResult(size_t index);
+ void SetResult(size_t index, QueryResult_AutoPtr result);
+};
+
+class SQLQueryHolderTask : public SQLOperation
+{
+ private:
+ SQLQueryHolder * m_holder;
+ Trinity::IQueryCallback * m_callback;
+ SQLResultQueue * m_queue;
+ public:
+ SQLQueryHolderTask(SQLQueryHolder *holder, Trinity::IQueryCallback * callback, SQLResultQueue * queue)
+ : m_holder(holder), m_callback(callback), m_queue(queue) {}
+ bool Execute();
+};
+
+class SQLQueryTask : public SQLOperation
+{
+ private:
+ const char *m_sql;
+ Trinity::IQueryCallback * m_callback;
+ SQLResultQueue * m_queue;
+ public:
+ SQLQueryTask(const char *sql, Trinity::IQueryCallback * callback, SQLResultQueue * queue)
+ : m_sql(strdup(sql)), m_callback(callback), m_queue(queue) {}
+ ~SQLQueryTask() { void* tofree = const_cast<char*>(m_sql); free(tofree); }
+ bool Execute();
+};
+
+
+#endif \ No newline at end of file
diff --git a/src/server/shared/Database/SQLStorage.cpp b/src/server/shared/Database/SQLStorage.cpp
index 1a65824a631..26aecb80fa3 100644
--- a/src/server/shared/Database/SQLStorage.cpp
+++ b/src/server/shared/Database/SQLStorage.cpp
@@ -21,7 +21,7 @@
#include "SQLStorage.h"
#include "SQLStorageImpl.h"
-extern Database WorldDatabase;
+extern DatabaseType WorldDatabase;
const char CreatureInfosrcfmt[]="iiiiiiiiiisssiiiiiiifffiffiifiiiiiiiiiiffiiiiiiiiiiiiiiiiiiiiiiiisiifffliiiiiiiliiisi";
const char CreatureInfodstfmt[]="iiiiiiiiiisssibbiiiifffiffiifiiiiiiiiiiffiiiiiiiiiiiiiiiiiiiiiiiisiifffliiiiiiiliiiii";
diff --git a/src/server/shared/Database/SqlOperations.h b/src/server/shared/Database/SqlOperations.h
deleted file mode 100644
index 337790e4c72..00000000000
--- a/src/server/shared/Database/SqlOperations.h
+++ /dev/null
@@ -1,168 +0,0 @@
-/*
- * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
- *
- * Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifndef __SQLOPERATIONS_H
-#define __SQLOPERATIONS_H
-
-#include "Common.h"
-
-#include "ace/Thread_Mutex.h"
-#include "ace/Method_Request.h"
-#include "Threading/LockedQueue.h"
-#include <queue>
-#include "Threading/Callback.h"
-#include "QueryResult.h"
-
-/// ---- BASE ---
-
-class Database;
-class SqlDelayThread;
-
-class SqlOperation
-{
- public:
- virtual void OnRemove() { delete this; }
- virtual void Execute(Database *db) = 0;
- virtual ~SqlOperation() {}
-};
-
-/// ---- ASYNC STATEMENTS / TRANSACTIONS ----
-
-class SqlStatement : public SqlOperation
-{
- private:
- const char *m_sql;
- public:
- SqlStatement(const char *sql) : m_sql(strdup(sql)){}
- ~SqlStatement() { void* tofree = const_cast<char*>(m_sql); free(tofree); }
- void Execute(Database *db);
-};
-
-class SqlTransaction : public SqlOperation
-{
- private:
- std::queue<const char*> m_queue;
- ACE_Thread_Mutex m_Mutex;
- public:
- SqlTransaction() {}
- void DelayExecute(const char *sql)
- {
- m_Mutex.acquire();
- char* _sql = strdup(sql);
- if (_sql)
- m_queue.push(_sql);
- m_Mutex.release();
- }
- void Execute(Database *db);
-};
-
-/// ---- ASYNC QUERIES ----
-
-class SqlQuery; /// contains a single async query
-class QueryResult; /// the result of one
-class SqlResultQueue; /// queue for thread sync
-class SqlQueryHolder; /// groups several async quries
-class SqlQueryHolderEx; /// points to a holder, added to the delay thread
-
-class SqlResultQueue : public ACE_Based::LockedQueue<Trinity::IQueryCallback* , ACE_Thread_Mutex>
-{
- public:
- SqlResultQueue() {}
- void Update();
-};
-
-class SqlQuery : public SqlOperation
-{
- private:
- const char *m_sql;
- Trinity::IQueryCallback * m_callback;
- SqlResultQueue * m_queue;
- public:
- SqlQuery(const char *sql, Trinity::IQueryCallback * callback, SqlResultQueue * queue)
- : m_sql(strdup(sql)), m_callback(callback), m_queue(queue) {}
- ~SqlQuery() { void* tofree = const_cast<char*>(m_sql); free(tofree); }
- void Execute(Database *db);
-};
-
-class SqlQueryHolder
-{
- friend class SqlQueryHolderEx;
- private:
- typedef std::pair<const char*, QueryResult_AutoPtr> SqlResultPair;
- std::vector<SqlResultPair> m_queries;
- public:
- SqlQueryHolder() {}
- ~SqlQueryHolder();
- bool SetQuery(size_t index, const char *sql);
- bool SetPQuery(size_t index, const char *format, ...) ATTR_PRINTF(3,4);
- void SetSize(size_t size);
- QueryResult_AutoPtr GetResult(size_t index);
- void SetResult(size_t index, QueryResult_AutoPtr result);
- bool Execute(Trinity::IQueryCallback * callback, SqlDelayThread *thread, SqlResultQueue *queue);
-};
-
-class SqlQueryHolderEx : public SqlOperation
-{
- private:
- SqlQueryHolder * m_holder;
- Trinity::IQueryCallback * m_callback;
- SqlResultQueue * m_queue;
- public:
- SqlQueryHolderEx(SqlQueryHolder *holder, Trinity::IQueryCallback * callback, SqlResultQueue * queue)
- : m_holder(holder), m_callback(callback), m_queue(queue) {}
- void Execute(Database *db);
-};
-
-class SqlAsyncTask : public ACE_Method_Request
-{
-public:
- SqlAsyncTask(Database * db, SqlOperation * op) : m_db(db), m_op(op){}
- ~SqlAsyncTask()
- {
- if (!m_op)
- return;
-
- delete m_op;
- m_op = NULL;
- }
-
- int call()
- {
- if (m_db == NULL || m_op == NULL)
- return -1;
-
- try
- {
- m_op->Execute(m_db);
- }
- catch(...)
- {
- return -1;
- }
-
- return 0;
- }
-
-private:
- Database * m_db;
- SqlOperation * m_op;
-};
-#endif //__SQLOPERATIONS_H
-
diff --git a/src/server/shared/PrecompiledHeaders/sharedPCH.h b/src/server/shared/PrecompiledHeaders/sharedPCH.h
index c3e00e5f119..289f31e74bf 100644
--- a/src/server/shared/PrecompiledHeaders/sharedPCH.h
+++ b/src/server/shared/PrecompiledHeaders/sharedPCH.h
@@ -6,8 +6,8 @@
#include "DatabaseEnv.h"
#include "Threading/Threading.h"
#include "Database/DatabaseEnv.h"
-#include "Database/SqlDelayThread.h"
-#include "Database/SqlOperations.h"
+#include "Database/DatabaseWorker.h"
+#include "Database/SQLOperation.h"
#include "Debugging/Errors.h"
#include "Dynamic/TypeList.h"
#include "Dynamic/UnorderedMap.h"
diff --git a/src/server/worldserver/CommandLine/CliRunnable.cpp b/src/server/worldserver/CommandLine/CliRunnable.cpp
index d105f29f3c2..e44ec1ada94 100644
--- a/src/server/worldserver/CommandLine/CliRunnable.cpp
+++ b/src/server/worldserver/CommandLine/CliRunnable.cpp
@@ -690,8 +690,28 @@ int kb_hit_return()
/// %Thread start
void CliRunnable::run()
{
- ///- Init new SQL thread for the world database (one connection call enough)
- WorldDatabase.ThreadStart(); // let thread do safe mySQL requests
+ ///- Init MySQL threads or connections
+ bool needInit = true;
+ if (!(sWorld.getConfig(CONFIG_MYSQL_BUNDLE_WORLDDB) & MYSQL_BUNDLE_RA))
+ {
+ WorldDatabase.Init_MySQL_Connection();
+ needInit = false;
+ }
+
+ if (!(sWorld.getConfig(CONFIG_MYSQL_BUNDLE_LOGINDB) & MYSQL_BUNDLE_RA))
+ {
+ LoginDatabase.Init_MySQL_Connection();
+ needInit = false;
+ }
+
+ if (!(sWorld.getConfig(CONFIG_MYSQL_BUNDLE_CHARDB) & MYSQL_BUNDLE_RA))
+ {
+ CharacterDatabase.Init_MySQL_Connection();
+ needInit = false;
+ }
+
+ if (needInit)
+ MySQL::Thread_Init();
char commandbuf[256];
@@ -759,6 +779,14 @@ void CliRunnable::run()
}
- ///- End the database thread
- WorldDatabase.ThreadEnd(); // free mySQL thread resources
+ ///- Free MySQL thread resources and deallocate lingering connections
+ if (!(sWorld.getConfig(CONFIG_MYSQL_BUNDLE_WORLDDB) & MYSQL_BUNDLE_RA))
+ WorldDatabase.End_MySQL_Connection();
+ if (!(sWorld.getConfig(CONFIG_MYSQL_BUNDLE_LOGINDB) & MYSQL_BUNDLE_RA))
+ LoginDatabase.End_MySQL_Connection();
+
+ if (!(sWorld.getConfig(CONFIG_MYSQL_BUNDLE_CHARDB) & MYSQL_BUNDLE_RA))
+ CharacterDatabase.End_MySQL_Connection();
+ if (needInit)
+ MySQL::Thread_End();
}
diff --git a/src/server/worldserver/Master.cpp b/src/server/worldserver/Master.cpp
index ce2f442fa8f..ab906cb9b42 100644
--- a/src/server/worldserver/Master.cpp
+++ b/src/server/worldserver/Master.cpp
@@ -370,9 +370,9 @@ int Master::Run()
clearOnlineAccounts();
///- Wait for delay threads to end
- CharacterDatabase.HaltDelayThread();
- WorldDatabase.HaltDelayThread();
- LoginDatabase.HaltDelayThread();
+ CharacterDatabase.Close();
+ WorldDatabase.Close();
+ LoginDatabase.Close();
sLog.outString( "Halting process..." );
@@ -439,8 +439,8 @@ bool Master::_StartDB()
{
sLog.SetLogDB(false);
std::string dbstring;
+ uint8 num_threads;
- ///- Get world database info from configuration file
dbstring = sConfig.GetStringDefault("WorldDatabaseInfo", "");
if (dbstring.empty())
{
@@ -448,13 +448,20 @@ bool Master::_StartDB()
return false;
}
- ///- Initialise the world database
- if( !WorldDatabase.Initialize(dbstring.c_str()))
+ num_threads = sConfig.GetIntDefault("WorldDatabase.WorkerThreads", 1);
+ if (num_threads < 1 || num_threads > 32)
{
- sLog.outError("Cannot connect to world database %s",dbstring.c_str());
+ sLog.outError("World database: invalid number of worker threads specified. "
+ "Please pick a value between 1 and 32.");
return false;
}
+ ///- Initialise the world database
+ if (!WorldDatabase.Open(dbstring, num_threads))
+ {
+ sLog.outError("Cannot connect to world database %s", dbstring.c_str());
+ return false;
+ }
///- Get character database info from configuration file
dbstring = sConfig.GetStringDefault("CharacterDatabaseInfo", "");
if (dbstring.empty())
@@ -463,13 +470,20 @@ bool Master::_StartDB()
return false;
}
- ///- Initialise the Character database
- if (!CharacterDatabase.Initialize(dbstring.c_str()))
+ num_threads = sConfig.GetIntDefault("CharacterDatabase.WorkerThreads", 1);
+ if (num_threads < 1 || num_threads > 32)
{
- sLog.outError("Cannot connect to Character database %s",dbstring.c_str());
+ sLog.outError("Character database: invalid number of worker threads specified. "
+ "Please pick a value between 1 and 32.");
return false;
}
+ ///- Initialise the Character database
+ if (!CharacterDatabase.Open(dbstring, num_threads))
+ {
+ sLog.outError("Cannot connect to Character database %s", dbstring.c_str());
+ return false;
+ }
///- Get login database info from configuration file
dbstring = sConfig.GetStringDefault("LoginDatabaseInfo", "");
if (dbstring.empty())
@@ -478,13 +492,20 @@ bool Master::_StartDB()
return false;
}
- ///- Initialise the login database
- if (!LoginDatabase.Initialize(dbstring.c_str()))
+ num_threads = sConfig.GetIntDefault("LoginDatabase.WorkerThreads", 1);
+ if (num_threads < 1 || num_threads > 32)
{
- sLog.outError("Cannot connect to login database %s",dbstring.c_str());
+ sLog.outError("Login database: invalid number of worker threads specified. "
+ "Please pick a value between 1 and 32.");
return false;
}
+ ///- Initialise the login database
+ if (!LoginDatabase.Open(dbstring, num_threads))
+ {
+ sLog.outError("Cannot connect to login database %s", dbstring.c_str());
+ return false;
+ }
///- Get the realm Id from the configuration file
realmID = sConfig.GetIntDefault("RealmID", 0);
if (!realmID)
diff --git a/src/server/worldserver/WorldThread/WorldRunnable.cpp b/src/server/worldserver/WorldThread/WorldRunnable.cpp
index 67a3937b97d..555f174b6c8 100644
--- a/src/server/worldserver/WorldThread/WorldRunnable.cpp
+++ b/src/server/worldserver/WorldThread/WorldRunnable.cpp
@@ -43,8 +43,27 @@ extern int m_ServiceStatus;
/// Heartbeat for the World
void WorldRunnable::run()
{
- ///- Init new SQL thread for the world database
- WorldDatabase.ThreadStart(); // let thread do safe mySQL requests (one connection call enough)
+ ///- Init MySQL threads or connections
+ bool needInit = true;
+ if (!(sWorld.getConfig(CONFIG_MYSQL_BUNDLE_WORLDDB) & MYSQL_BUNDLE_RA))
+ {
+ WorldDatabase.Init_MySQL_Connection();
+ needInit = false;
+ }
+ if (!(sWorld.getConfig(CONFIG_MYSQL_BUNDLE_LOGINDB) & MYSQL_BUNDLE_RA))
+ {
+ LoginDatabase.Init_MySQL_Connection();
+ needInit = false;
+ }
+
+ if (!(sWorld.getConfig(CONFIG_MYSQL_BUNDLE_CHARDB) & MYSQL_BUNDLE_RA))
+ {
+ CharacterDatabase.Init_MySQL_Connection();
+ needInit = false;
+ }
+
+ if (needInit)
+ MySQL::Thread_Init();
sWorld.InitResultQueue();
@@ -99,6 +118,16 @@ void WorldRunnable::run()
sMapMgr.UnloadAll(); // unload all grids (including locked in memory)
- ///- End the database thread
- WorldDatabase.ThreadEnd(); // free mySQL thread resources
+ ///- Free MySQL thread resources and deallocate lingering connections
+ if (!(sWorld.getConfig(CONFIG_MYSQL_BUNDLE_WORLDDB) & MYSQL_BUNDLE_RA))
+ WorldDatabase.End_MySQL_Connection();
+
+ if (!(sWorld.getConfig(CONFIG_MYSQL_BUNDLE_LOGINDB) & MYSQL_BUNDLE_RA))
+ LoginDatabase.End_MySQL_Connection();
+
+ if (!(sWorld.getConfig(CONFIG_MYSQL_BUNDLE_CHARDB) & MYSQL_BUNDLE_RA))
+ CharacterDatabase.End_MySQL_Connection();
+
+ if (needInit)
+ MySQL::Thread_End();
}
diff --git a/src/server/worldserver/worldserver.conf.dist b/src/server/worldserver/worldserver.conf.dist
index 90a520529cc..d847a7c0467 100644
--- a/src/server/worldserver/worldserver.conf.dist
+++ b/src/server/worldserver/worldserver.conf.dist
@@ -36,6 +36,30 @@
# .;/path/to/unix_socket;username;password;database
# - use Unix sockets in Unix/Linux
#
+# LoginDatabase.WorkerThreads
+# WorldDatabase.WorkerThreads
+# CharacterDatabase.WorkerThreads
+# The amount of worker threads spawned to handle
+# asynchroneous MySQL statements
+# Each worker thread is mirrored with its own
+# connection to the MySQL server and their own
+# thread on the MySQL server.
+# Default: 1
+#
+# LoginDatabase.ThreadBundleMask
+# WorldDatabase.ThreadBundleMask
+# CharacterDatabase.ThreadBundleMask
+# Defines which runnable threads are bundled into one synchroneous
+# connection. Runnables not specified in the mask will have their
+# seperate connection to the MySQL server.
+# Value is a bitmask consisting of:
+# MYSQL_BUNDLE_NONE = 0, Each task will run their own MySQL connection
+# MYSQL_BUNDLE_CLI = 1, Commandline interface thread
+# MYSQL_BUNDLE_RA = 2, Remote admin thread
+# MYSQL_BUNDLE_RAR = 4, Reactor runnable thread
+# MYSQL_BUNDLE_WORLD = 8, WorldRunnable
+# MYSQL_BUNDLE_ALL = 15, All bundled together
+#
# MaxPingTime
# Settings for maximum database-ping interval (minutes between pings)
#
@@ -53,6 +77,12 @@ LogsDir = ""
LoginDatabaseInfo = "127.0.0.1;3306;trinity;trinity;auth"
WorldDatabaseInfo = "127.0.0.1;3306;trinity;trinity;world"
CharacterDatabaseInfo = "127.0.0.1;3306;trinity;trinity;characters"
+LoginDatabase.WorkerThreads = 1
+WorldDatabase.WorkerThreads = 1
+CharacterDatabase.WorkerThreads = 1
+LoginDatabase.ThreadBundleMask = 15
+WorldDatabase.ThreadBundleMask = 15
+CharacterDatabase.ThreadBundleMask = 15
MaxPingTime = 30
WorldServerPort = 8085
BindIP = "0.0.0.0"