* 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
This commit is contained in:
Machiavelli
2010-08-18 02:25:52 +02:00
parent 1ab2bd6d58
commit 87218eadcd
39 changed files with 1568 additions and 731 deletions
+11 -11
View File
@@ -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;
}
+27 -11
View File
@@ -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
+8 -15
View File
@@ -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;
}
+8 -8
View File
@@ -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
+26 -26
View File
@@ -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);
@@ -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();
}
@@ -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)
+2 -2
View File
@@ -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,"
+1 -1
View File
@@ -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);
+6 -5
View File
@@ -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;
}
+4 -2
View File
@@ -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;
}
};
@@ -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());
@@ -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"
@@ -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"
+23 -2
View File
@@ -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");
+1 -2
View File
@@ -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();
+7 -2
View File
@@ -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);
}
+5 -2
View File
@@ -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;
@@ -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
+6 -2
View File
@@ -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
-234
View File
@@ -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
@@ -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.
}
@@ -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
@@ -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;
}
@@ -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
@@ -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");
}
@@ -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
@@ -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
@@ -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;
}
@@ -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
@@ -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 ----
void SqlStatement::Execute(Database *db)
/*! Basic, ad-hoc queries. */
BasicStatementTask::BasicStatementTask(const char* sql)
{
/// just do it
db->DirectExecute(m_sql);
m_sql = strdup(sql);
}
void SqlTransaction::Execute(Database *db)
BasicStatementTask::~BasicStatementTask()
{
free((void*)m_sql);
}
bool BasicStatementTask::Execute()
{
return m_conn->Execute(m_sql);
}
/*! Transactions. */
TransactionTask::TransactionTask()
{
}
TransactionTask::~TransactionTask()
{
}
void TransactionTask::ForcefulDelete()
{
while (!m_queries.empty())
{
free((void*)const_cast<char*>(m_queries.front()));
m_queries.pop();
}
}
bool TransactionTask::Execute()
{
if (m_queries.empty())
return false;
const char* sql;
m_Mutex.acquire();
if (m_queue.empty())
m_conn->BeginTransaction();
while (!m_queries.empty())
{
m_Mutex.release();
return;
}
db->DirectExecute("START TRANSACTION");
while (!m_queue.empty())
{
sql = m_queue.front();
if (!db->DirectExecute(sql))
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();
m_conn->CommitTransaction();
return true;
}
/// ---- 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);
}
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;
}
+122
View File
@@ -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
+1 -1
View File
@@ -21,7 +21,7 @@
#include "SQLStorage.h"
#include "SQLStorageImpl.h"
extern Database WorldDatabase;
extern DatabaseType WorldDatabase;
const char CreatureInfosrcfmt[]="iiiiiiiiiisssiiiiiiifffiffiifiiiiiiiiiiffiiiiiiiiiiiiiiiiiiiiiiiisiifffliiiiiiiliiisi";
const char CreatureInfodstfmt[]="iiiiiiiiiisssibbiiiifffiffiifiiiiiiiiiiffiiiiiiiiiiiiiiiiiiiiiiiisiifffliiiiiiiliiiii";
-168
View File
@@ -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
@@ -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"
@@ -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();
}
+34 -13
View File
@@ -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)
@@ -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();
}
@@ -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"