[11054] Do not allow async transaction execution while server is loading. Call Database::InitDelayThread() function explicitly to create async DB worker thread after server initialization is complete.

Signed-off-by: Ambal <pogrebniak@gala.net>
This commit is contained in:
Ambal 2011-01-20 23:46:44 +02:00
parent e6e7bf8573
commit 07c9f0cbb8
9 changed files with 59 additions and 58 deletions

View file

@ -514,7 +514,7 @@ void InstanceSaveManager::CleanupInstances()
CharacterDatabase.Execute("DELETE FROM creature_respawn WHERE instance <> 0 AND instance NOT IN (SELECT id FROM instance)"); CharacterDatabase.Execute("DELETE FROM creature_respawn WHERE instance <> 0 AND instance NOT IN (SELECT id FROM instance)");
CharacterDatabase.Execute("DELETE FROM gameobject_respawn WHERE instance <> 0 AND instance NOT IN (SELECT id FROM instance)"); CharacterDatabase.Execute("DELETE FROM gameobject_respawn WHERE instance <> 0 AND instance NOT IN (SELECT id FROM instance)");
//execute transaction directly //execute transaction directly
CharacterDatabase.CommitTransactionDirect(); CharacterDatabase.CommitTransaction();
bar.step(); bar.step();
sLog.outString(); sLog.outString();
@ -562,7 +562,7 @@ void InstanceSaveManager::PackInstances()
CharacterDatabase.PExecute("UPDATE instance SET id = '%u' WHERE id = '%u'", InstanceNumber, *i); CharacterDatabase.PExecute("UPDATE instance SET id = '%u' WHERE id = '%u'", InstanceNumber, *i);
CharacterDatabase.PExecute("UPDATE group_instance SET instance = '%u' WHERE instance = '%u'", InstanceNumber, *i); CharacterDatabase.PExecute("UPDATE group_instance SET instance = '%u' WHERE instance = '%u'", InstanceNumber, *i);
//execute transaction synchronously //execute transaction synchronously
CharacterDatabase.CommitTransactionDirect(); CharacterDatabase.CommitTransaction();
} }
++InstanceNumber; ++InstanceNumber;

View file

@ -5598,7 +5598,7 @@ void ObjectMgr::PackGroupIds()
CharacterDatabase.BeginTransaction(); CharacterDatabase.BeginTransaction();
CharacterDatabase.PExecute("DELETE FROM groups WHERE groupId = '%u'", id); CharacterDatabase.PExecute("DELETE FROM groups WHERE groupId = '%u'", id);
CharacterDatabase.PExecute("DELETE FROM group_member WHERE groupId = '%u'", id); CharacterDatabase.PExecute("DELETE FROM group_member WHERE groupId = '%u'", id);
CharacterDatabase.CommitTransactionDirect(); CharacterDatabase.CommitTransaction();
continue; continue;
} }
@ -5621,7 +5621,7 @@ void ObjectMgr::PackGroupIds()
CharacterDatabase.BeginTransaction(); CharacterDatabase.BeginTransaction();
CharacterDatabase.PExecute("UPDATE groups SET groupId = '%u' WHERE groupId = '%u'", groupId, *i); CharacterDatabase.PExecute("UPDATE groups SET groupId = '%u' WHERE groupId = '%u'", groupId, *i);
CharacterDatabase.PExecute("UPDATE group_member SET groupId = '%u' WHERE groupId = '%u'", groupId, *i); CharacterDatabase.PExecute("UPDATE group_member SET groupId = '%u' WHERE groupId = '%u'", groupId, *i);
CharacterDatabase.CommitTransactionDirect(); CharacterDatabase.CommitTransaction();
} }
++groupId; ++groupId;
@ -5670,7 +5670,7 @@ void ObjectMgr::SetHighestGuids()
CharacterDatabase.PExecute("DELETE FROM mail_items WHERE item_guid >= '%u'", m_ItemGuids.GetNextAfterMaxUsed()); CharacterDatabase.PExecute("DELETE FROM mail_items WHERE item_guid >= '%u'", m_ItemGuids.GetNextAfterMaxUsed());
CharacterDatabase.PExecute("DELETE FROM auction WHERE itemguid >= '%u'", m_ItemGuids.GetNextAfterMaxUsed()); CharacterDatabase.PExecute("DELETE FROM auction WHERE itemguid >= '%u'", m_ItemGuids.GetNextAfterMaxUsed());
CharacterDatabase.PExecute("DELETE FROM guild_bank_item WHERE item_guid >= '%u'", m_ItemGuids.GetNextAfterMaxUsed()); CharacterDatabase.PExecute("DELETE FROM guild_bank_item WHERE item_guid >= '%u'", m_ItemGuids.GetNextAfterMaxUsed());
CharacterDatabase.CommitTransactionDirect(); CharacterDatabase.CommitTransaction();
result = WorldDatabase.Query("SELECT MAX(guid) FROM gameobject" ); result = WorldDatabase.Query("SELECT MAX(guid) FROM gameobject" );
if( result ) if( result )

View file

@ -197,6 +197,12 @@ int Master::Run()
///- Initialize the World ///- Initialize the World
sWorld.SetInitialWorldSettings(); sWorld.SetInitialWorldSettings();
//server loaded successfully => enable async DB requests
//this is done to forbid any async transactions during server startup!
CharacterDatabase.InitDelayThread();
WorldDatabase.InitDelayThread();
LoginDatabase.InitDelayThread();
///- Catch termination signals ///- Catch termination signals
_HookSignals(); _HookSignals();
@ -208,7 +214,7 @@ int Master::Run()
{ {
std::string builds = AcceptableClientBuildsListStr(); std::string builds = AcceptableClientBuildsListStr();
LoginDatabase.escape_string(builds); LoginDatabase.escape_string(builds);
LoginDatabase.PExecute("UPDATE realmlist SET realmflags = realmflags & ~(%u), population = 0, realmbuilds = '%s' WHERE id = '%u'", REALM_FLAG_OFFLINE, builds.c_str(), realmID); LoginDatabase.DirectPExecute("UPDATE realmlist SET realmflags = realmflags & ~(%u), population = 0, realmbuilds = '%s' WHERE id = '%u'", REALM_FLAG_OFFLINE, builds.c_str(), realmID);
} }
ACE_Based::Thread* cliThread = NULL; ACE_Based::Thread* cliThread = NULL;
@ -328,7 +334,7 @@ int Master::Run()
} }
///- Set server offline in realmlist ///- Set server offline in realmlist
LoginDatabase.PExecute("UPDATE realmlist SET realmflags = realmflags | %u WHERE id = '%u'", REALM_FLAG_OFFLINE, realmID); LoginDatabase.DirectPExecute("UPDATE realmlist SET realmflags = realmflags | %u WHERE id = '%u'", REALM_FLAG_OFFLINE, realmID);
///- Remove signal handling before leaving ///- Remove signal handling before leaving
_UnhookSignals(); _UnhookSignals();

View file

@ -221,8 +221,10 @@ extern int main(int argc, char **argv)
// cleanup query // cleanup query
// set expired bans to inactive // set expired bans to inactive
LoginDatabase.BeginTransaction();
LoginDatabase.Execute("UPDATE account_banned SET active = 0 WHERE unbandate<=UNIX_TIMESTAMP() AND unbandate<>bandate"); LoginDatabase.Execute("UPDATE account_banned SET active = 0 WHERE unbandate<=UNIX_TIMESTAMP() AND unbandate<>bandate");
LoginDatabase.Execute("DELETE FROM ip_banned WHERE unbandate<=UNIX_TIMESTAMP() AND unbandate<>bandate"); LoginDatabase.Execute("DELETE FROM ip_banned WHERE unbandate<=UNIX_TIMESTAMP() AND unbandate<>bandate");
LoginDatabase.CommitTransaction();
///- Launch the listening network socket ///- Launch the listening network socket
ACE_Acceptor<AuthSocket, ACE_SOCK_Acceptor> acceptor; ACE_Acceptor<AuthSocket, ACE_SOCK_Acceptor> acceptor;
@ -285,6 +287,9 @@ extern int main(int argc, char **argv)
} }
#endif #endif
//server has started up successfully => enable async DB requests
LoginDatabase.InitDelayThread();
// maximum counter for next ping // maximum counter for next ping
uint32 numLoops = (sConfig.GetIntDefault( "MaxPingTime", 30 ) * (MINUTE * 1000000 / 100000)); uint32 numLoops = (sConfig.GetIntDefault( "MaxPingTime", 30 ) * (MINUTE * 1000000 / 100000));
uint32 loopCounter = 0; uint32 loopCounter = 0;

View file

@ -29,13 +29,7 @@
Database::~Database() Database::~Database()
{ {
HaltDelayThread(); StopServer();
/*Delete objects*/
delete m_pResultQueue;
delete m_pAsyncConn;
for (int i = 0; i < m_pQueryConnections.size(); ++i)
delete m_pQueryConnections[i];
} }
bool Database::Initialize(const char * infoString, int nConns /*= 1*/) bool Database::Initialize(const char * infoString, int nConns /*= 1*/)
@ -80,10 +74,33 @@ bool Database::Initialize(const char * infoString, int nConns /*= 1*/)
if(!m_pAsyncConn->Initialize(infoString)) if(!m_pAsyncConn->Initialize(infoString))
return false; return false;
InitDelayThread(); m_pResultQueue = new SqlResultQueue;
return true; return true;
} }
void Database::StopServer()
{
HaltDelayThread();
/*Delete objects*/
if(m_pResultQueue)
{
delete m_pResultQueue;
m_pResultQueue = NULL;
}
if(m_pAsyncConn)
{
delete m_pAsyncConn;
m_pAsyncConn = NULL;
}
for (size_t i = 0; i < m_pQueryConnections.size(); ++i)
delete m_pQueryConnections[i];
m_pQueryConnections.clear();
}
SqlDelayThread * Database::CreateDelayThread() SqlDelayThread * Database::CreateDelayThread()
{ {
assert(m_pAsyncConn); assert(m_pAsyncConn);
@ -94,7 +111,6 @@ void Database::InitDelayThread()
{ {
assert(!m_delayThread); assert(!m_delayThread);
m_pResultQueue = new SqlResultQueue;
//New delay thread for delay execute //New delay thread for delay execute
m_threadBody = CreateDelayThread(); // will deleted at m_delayThread delete m_threadBody = CreateDelayThread(); // will deleted at m_delayThread delete
m_delayThread = new ACE_Based::Thread(m_threadBody); m_delayThread = new ACE_Based::Thread(m_threadBody);
@ -109,14 +125,6 @@ void Database::HaltDelayThread()
delete m_delayThread; //This also deletes m_threadBody delete m_delayThread; //This also deletes m_threadBody
m_delayThread = NULL; m_delayThread = NULL;
m_threadBody = NULL; m_threadBody = NULL;
//stop async result queue
if(m_pResultQueue)
{
m_pResultQueue->Update();
delete m_pResultQueue;
m_pResultQueue = NULL;
}
} }
void Database::ThreadStart() void Database::ThreadStart()
@ -268,6 +276,10 @@ bool Database::Execute(const char *sql)
} }
else else
{ {
//if async execution is not available
if(!m_threadBody)
return DirectExecute(sql);
// Simple sql statement // Simple sql statement
pTrans = new SqlTransaction; pTrans = new SqlTransaction;
pTrans->DelayExecute(sql); pTrans->DelayExecute(sql);
@ -350,6 +362,10 @@ bool Database::CommitTransaction()
if(!m_TransStorage->get()) if(!m_TransStorage->get())
return false; return false;
//if async execution is not available
if(!m_delayThread)
return CommitTransactionDirect();
//add SqlTransaction to the async queue //add SqlTransaction to the async queue
m_threadBody->Delay(m_TransStorage->detach()); m_threadBody->Delay(m_TransStorage->detach());
return true; return true;

View file

@ -81,7 +81,11 @@ class MANGOS_DLL_SPEC Database
virtual ~Database(); virtual ~Database();
virtual bool Initialize(const char *infoString, int nConns = 1); virtual bool Initialize(const char *infoString, int nConns = 1);
//start worker thread for async DB request execution
//you should call it explicitly after your server successfully started up
//NO ASYNC TRANSACTIONS DURING SERVER STARTUP - ONLY DURING RUNTIME!!!
virtual void InitDelayThread(); virtual void InitDelayThread();
//stop worker thread
virtual void HaltDelayThread(); virtual void HaltDelayThread();
/// Synchronous DB queries /// Synchronous DB queries
@ -181,6 +185,8 @@ class MANGOS_DLL_SPEC Database
m_nQueryCounter = -1; m_nQueryCounter = -1;
} }
void StopServer();
//factory method to create SqlConnection objects //factory method to create SqlConnection objects
virtual SqlConnection * CreateConnection() = 0; virtual SqlConnection * CreateConnection() = 0;
//factory method to create SqlDelayThread objects //factory method to create SqlDelayThread objects

View file

@ -56,23 +56,7 @@ DatabaseMysql::DatabaseMysql()
DatabaseMysql::~DatabaseMysql() DatabaseMysql::~DatabaseMysql()
{ {
if (m_delayThread) StopServer();
HaltDelayThread();
//destroy SqlConnection objects
if(m_pQueryConnections.size())
{
for (int i = 0; i < m_pQueryConnections.size(); ++i)
delete m_pQueryConnections[i];
m_pQueryConnections.clear();
}
if(m_pAsyncConn)
{
delete m_pAsyncConn;
m_pAsyncConn = NULL;
}
//Free Mysql library pointers for last ~DB //Free Mysql library pointers for last ~DB
if(--db_count == 0) if(--db_count == 0)

View file

@ -43,23 +43,7 @@ DatabasePostgre::DatabasePostgre()
DatabasePostgre::~DatabasePostgre() DatabasePostgre::~DatabasePostgre()
{ {
if (m_delayThread)
HaltDelayThread();
//destroy SqlConnection objects
if(m_pQueryConnections.size())
{
for (int i = 0; i < m_pQueryConnections.size(); ++i)
delete m_pQueryConnections[i];
m_pQueryConnections.clear();
}
if(m_pAsyncConn)
{
delete m_pAsyncConn;
m_pAsyncConn = NULL;
}
} }
SqlConnection * DatabasePostgre::CreateConnection() SqlConnection * DatabasePostgre::CreateConnection()

View file

@ -1,4 +1,4 @@
#ifndef __REVISION_NR_H__ #ifndef __REVISION_NR_H__
#define __REVISION_NR_H__ #define __REVISION_NR_H__
#define REVISION_NR "11053" #define REVISION_NR "11054"
#endif // __REVISION_NR_H__ #endif // __REVISION_NR_H__