Skip to content

Commit

Permalink
[11054] Do not allow async transaction execution while server is load…
Browse files Browse the repository at this point in the history
…ing. Call Database::InitDelayThread() function explicitly to create async DB worker thread after server initialization is complete.

Signed-off-by: Ambal <pogrebniak@gala.net>
  • Loading branch information
Ambal committed Jan 20, 2011
1 parent 51ee834 commit 8048e00
Show file tree
Hide file tree
Showing 9 changed files with 59 additions and 58 deletions.
4 changes: 2 additions & 2 deletions src/game/InstanceSaveMgr.cpp
Expand Up @@ -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 gameobject_respawn WHERE instance <> 0 AND instance NOT IN (SELECT id FROM instance)");
//execute transaction directly
CharacterDatabase.CommitTransactionDirect();
CharacterDatabase.CommitTransaction();

bar.step();
sLog.outString();
Expand Down Expand Up @@ -562,7 +562,7 @@ void InstanceSaveManager::PackInstances()
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);
//execute transaction synchronously
CharacterDatabase.CommitTransactionDirect();
CharacterDatabase.CommitTransaction();
}

++InstanceNumber;
Expand Down
6 changes: 3 additions & 3 deletions src/game/ObjectMgr.cpp
Expand Up @@ -5598,7 +5598,7 @@ void ObjectMgr::PackGroupIds()
CharacterDatabase.BeginTransaction();
CharacterDatabase.PExecute("DELETE FROM groups WHERE groupId = '%u'", id);
CharacterDatabase.PExecute("DELETE FROM group_member WHERE groupId = '%u'", id);
CharacterDatabase.CommitTransactionDirect();
CharacterDatabase.CommitTransaction();
continue;
}

Expand All @@ -5621,7 +5621,7 @@ void ObjectMgr::PackGroupIds()
CharacterDatabase.BeginTransaction();
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.CommitTransactionDirect();
CharacterDatabase.CommitTransaction();
}

++groupId;
Expand Down Expand Up @@ -5670,7 +5670,7 @@ void ObjectMgr::SetHighestGuids()
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 guild_bank_item WHERE item_guid >= '%u'", m_ItemGuids.GetNextAfterMaxUsed());
CharacterDatabase.CommitTransactionDirect();
CharacterDatabase.CommitTransaction();

result = WorldDatabase.Query("SELECT MAX(guid) FROM gameobject" );
if( result )
Expand Down
10 changes: 8 additions & 2 deletions src/mangosd/Master.cpp
Expand Up @@ -197,6 +197,12 @@ int Master::Run()
///- Initialize the World
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
_HookSignals();

Expand All @@ -208,7 +214,7 @@ int Master::Run()
{
std::string builds = AcceptableClientBuildsListStr();
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;
Expand Down Expand Up @@ -328,7 +334,7 @@ int Master::Run()
}

///- 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
_UnhookSignals();
Expand Down
5 changes: 5 additions & 0 deletions src/realmd/Main.cpp
Expand Up @@ -221,8 +221,10 @@ extern int main(int argc, char **argv)

// cleanup query
// set expired bans to inactive
LoginDatabase.BeginTransaction();
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.CommitTransaction();

///- Launch the listening network socket
ACE_Acceptor<AuthSocket, ACE_SOCK_Acceptor> acceptor;
Expand Down Expand Up @@ -285,6 +287,9 @@ extern int main(int argc, char **argv)
}
#endif

//server has started up successfully => enable async DB requests
LoginDatabase.InitDelayThread();

// maximum counter for next ping
uint32 numLoops = (sConfig.GetIntDefault( "MaxPingTime", 30 ) * (MINUTE * 1000000 / 100000));
uint32 loopCounter = 0;
Expand Down
50 changes: 33 additions & 17 deletions src/shared/Database/Database.cpp
Expand Up @@ -29,13 +29,7 @@

Database::~Database()
{
HaltDelayThread();
/*Delete objects*/
delete m_pResultQueue;
delete m_pAsyncConn;

for (int i = 0; i < m_pQueryConnections.size(); ++i)
delete m_pQueryConnections[i];
StopServer();
}

bool Database::Initialize(const char * infoString, int nConns /*= 1*/)
Expand Down Expand Up @@ -80,10 +74,33 @@ bool Database::Initialize(const char * infoString, int nConns /*= 1*/)
if(!m_pAsyncConn->Initialize(infoString))
return false;

InitDelayThread();
m_pResultQueue = new SqlResultQueue;
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()
{
assert(m_pAsyncConn);
Expand All @@ -94,7 +111,6 @@ void Database::InitDelayThread()
{
assert(!m_delayThread);

m_pResultQueue = new SqlResultQueue;
//New delay thread for delay execute
m_threadBody = CreateDelayThread(); // will deleted at m_delayThread delete
m_delayThread = new ACE_Based::Thread(m_threadBody);
Expand All @@ -109,14 +125,6 @@ void Database::HaltDelayThread()
delete m_delayThread; //This also deletes m_threadBody
m_delayThread = NULL;
m_threadBody = NULL;

//stop async result queue
if(m_pResultQueue)
{
m_pResultQueue->Update();
delete m_pResultQueue;
m_pResultQueue = NULL;
}
}

void Database::ThreadStart()
Expand Down Expand Up @@ -268,6 +276,10 @@ bool Database::Execute(const char *sql)
}
else
{
//if async execution is not available
if(!m_threadBody)
return DirectExecute(sql);

// Simple sql statement
pTrans = new SqlTransaction;
pTrans->DelayExecute(sql);
Expand Down Expand Up @@ -350,6 +362,10 @@ bool Database::CommitTransaction()
if(!m_TransStorage->get())
return false;

//if async execution is not available
if(!m_delayThread)
return CommitTransactionDirect();

//add SqlTransaction to the async queue
m_threadBody->Delay(m_TransStorage->detach());
return true;
Expand Down
6 changes: 6 additions & 0 deletions src/shared/Database/Database.h
Expand Up @@ -81,7 +81,11 @@ class MANGOS_DLL_SPEC Database
virtual ~Database();

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();
//stop worker thread
virtual void HaltDelayThread();

/// Synchronous DB queries
Expand Down Expand Up @@ -181,6 +185,8 @@ class MANGOS_DLL_SPEC Database
m_nQueryCounter = -1;
}

void StopServer();

//factory method to create SqlConnection objects
virtual SqlConnection * CreateConnection() = 0;
//factory method to create SqlDelayThread objects
Expand Down
18 changes: 1 addition & 17 deletions src/shared/Database/DatabaseMysql.cpp
Expand Up @@ -56,23 +56,7 @@ DatabaseMysql::DatabaseMysql()

DatabaseMysql::~DatabaseMysql()
{
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;
}
StopServer();

//Free Mysql library pointers for last ~DB
if(--db_count == 0)
Expand Down
16 changes: 0 additions & 16 deletions src/shared/Database/DatabasePostgre.cpp
Expand Up @@ -43,23 +43,7 @@ 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()
Expand Down
2 changes: 1 addition & 1 deletion src/shared/revision_nr.h
@@ -1,4 +1,4 @@
#ifndef __REVISION_NR_H__
#define __REVISION_NR_H__
#define REVISION_NR "11053"
#define REVISION_NR "11054"
#endif // __REVISION_NR_H__

2 comments on commit 8048e00

@Axxus
Copy link

@Axxus Axxus commented on 8048e00 Jan 20, 2011

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Ambal
Copy link
Contributor

@Ambal Ambal commented on 8048e00 Jan 21, 2011

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for report, Axxus. As a temporary fix in your Database::Initialize() function:

if(!m_pAsyncConn->Initialize(infoString))
    return false;

m_pResultQueue = new SqlResultQueue;

InitDelayThread(); //<= add this function call
return true;

I'll submit fix for this issue thi evening

Please sign in to comment.