Core/DBLayer:

- DB Threading model update
* Get rid of ThreadBundleMask and bundled connection
* Implement configurable amount of Synch threads for databasepools
* Use modulus based algorithm to check for free synchronous connections instead of previous ¨get connection by thread key or bundlemask¨ feature
* Locks on mysql context objects are now managed outside the mysql query methods

Fixes issue #4058
Fixes issue #4059
Introduces a ton of more issues. Use at own risk. You were warned. Really.

Don´t forget to update your worldserver.conf

--HG--
branch : trunk
This commit is contained in:
Machiavelli
2010-09-27 00:20:56 +02:00
parent 894b2081b3
commit a9e9a2c884
11 changed files with 172 additions and 241 deletions

View File

@@ -339,15 +339,22 @@ bool StartDB()
return false;
}
uint8 num_threads = sConfig.GetIntDefault("LoginDatabase.WorkerThreads", 1);
if (num_threads < 1 || num_threads > 32)
uint8 worker_threads = sConfig.GetIntDefault("LoginDatabase.WorkerThreads", 1);
if (worker_threads < 1 || worker_threads > 32)
{
sLog.outError("Improper value specified for LoginDatabase.WorkerThreads, defaulting to 1.");
num_threads = 1;
worker_threads = 1;
}
//- Authserver has singlethreaded synchronous DB access, hence MYSQL_BUNDLE_ALL
if (!LoginDatabase.Open(dbstring.c_str(), num_threads, MYSQL_BUNDLE_ALL))
uint8 synch_threads = sConfig.GetIntDefault("LoginDatabase.SynchThreads", 1);
if (synch_threads < 1 || synch_threads > 32)
{
sLog.outError("Improper value specified for LoginDatabase.SynchThreads, defaulting to 1.");
synch_threads = 1;
}
/// NOTE: While authserver is singlethreaded you should keep synch_threads == 1. Increasing it is just silly since only 1 will be used ever.
if (!LoginDatabase.Open(dbstring.c_str(), worker_threads, synch_threads))
{
sLog.outError("Cannot connect to database");
return false;

View File

@@ -16,8 +16,6 @@ class WDBThreadStartReq1 : public ACE_Method_Request
virtual int call()
{
WorldDatabase.Init_MySQL_Connection();
CharacterDatabase.Init_MySQL_Connection();
return 0;
}
};
@@ -32,8 +30,6 @@ class WDBThreadEndReq1 : public ACE_Method_Request
virtual int call()
{
WorldDatabase.End_MySQL_Connection();
CharacterDatabase.End_MySQL_Connection();
return 0;
}
};

View File

@@ -158,16 +158,6 @@ class ReactorRunnable : protected ACE_Task_Base
{
sLog.outStaticDebug ("Network Thread Starting");
bool needInit = true;
if (!(LoginDatabase.GetBundleMask() & MYSQL_BUNDLE_RAR))
{
LoginDatabase.Init_MySQL_Connection();
needInit = false;
}
if (needInit)
MySQL::Thread_Init();
ACE_ASSERT (m_Reactor);
SocketSet::iterator i, t;
@@ -203,13 +193,6 @@ class ReactorRunnable : protected ACE_Task_Base
}
}
///- Free MySQL thread resources and deallocate lingering connections
if (!(LoginDatabase.GetBundleMask() & MYSQL_BUNDLE_RAR))
LoginDatabase.End_MySQL_Connection();
if (needInit)
MySQL::Thread_End();
sLog.outStaticDebug ("Network Thread Exitting");
return 0;

View File

@@ -35,8 +35,6 @@ int DatabaseWorker::svc()
if (!m_queue)
return -1;
MySQL::Thread_Init();
SQLOperation *request = NULL;
while (1)
{
@@ -50,8 +48,7 @@ int DatabaseWorker::svc()
delete request;
}
MySQL::Thread_End();
delete m_conn;
m_conn->Close();
return 0;
}

View File

@@ -24,7 +24,7 @@
class MySQLConnection;
class DatabaseWorker : protected ACE_Task_Base
class DatabaseWorker : public ACE_Task_Base
{
public:
DatabaseWorker(ACE_Activation_Queue* new_queue, MySQLConnection* con);

View File

@@ -33,23 +33,20 @@
#include "QueryHolder.h"
#include "AdhocStatement.h"
enum MySQLThreadBundle
{
MYSQL_BUNDLE_NONE = 0x00, //- Each task will run their own MySQL connection
MYSQL_BUNDLE_UNUSED = 0x01, //- Temp unused
MYSQL_BUNDLE_RA = 0x02, //- Remote admin thread
MYSQL_BUNDLE_RAR = 0x04, //- Reactor runnable thread
MYSQL_BUNDLE_WORLD = 0x08, //- WorldRunnable
MYSQL_BUNDLE_ALL = MYSQL_BUNDLE_RA | MYSQL_BUNDLE_RAR | MYSQL_BUNDLE_WORLD,
};
class PingOperation : public SQLOperation
{
/// Operation for idle delaythreads
bool Execute()
{
m_conn->Ping();
return true;
for (;;)
if (m_conn->LockIfReady())
{
m_conn->Ping();
m_conn->Unlock();
return true;
}
return false;
}
};
@@ -57,7 +54,6 @@ template <class T>
class DatabaseWorkerPool
{
private:
typedef UNORDERED_MAP<ACE_Based::Thread*, MySQLConnection*> ConnectionMap;
typedef ACE_Atomic_Op<ACE_SYNCH_MUTEX, uint32> AtomicUInt;
public:
@@ -66,6 +62,7 @@ class DatabaseWorkerPool
m_connections(0)
{
m_infoString = "";
m_connections.resize(IDX_SIZE);
mysql_library_init(-1, NULL, NULL);
WPFatal (mysql_thread_safe(), "Used MySQL library isn't thread-safe.");
@@ -73,97 +70,69 @@ class DatabaseWorkerPool
~DatabaseWorkerPool()
{
sLog.outSQLDriver("~DatabaseWorkerPool for '%s'.", "missingname");
mysql_library_end();
}
bool Open(const std::string& infoString, uint8 num_threads, MySQLThreadBundle mask)
bool Open(const std::string& infoString, uint8 async_threads, uint8 synch_threads)
{
//- Only created bundled connection if configured
m_bundle_conn = NULL;
if (mask != MYSQL_BUNDLE_NONE)
sLog.outSQLDriver("Opening databasepool '%s'. Async threads: %u, synch threads: %u", "nonameyet", async_threads, synch_threads);
/// Open asynchronous connections (delayed operations)
m_connections[IDX_ASYNC].resize(async_threads);
for (uint8 i = 0; i < async_threads; ++i)
{
sLog.outSQLDriver("Creating bundled/master MySQL connection.");
m_bundle_conn = new T();
m_bundle_conn->Open(infoString);
++m_connections;
T* t = new T(m_queue);
t->Open(infoString);
m_connections[IDX_ASYNC][i] = t;
++m_connectionCount;
}
m_async_connections.resize(num_threads);
/// Open the Async pool
for (uint8 i = 0; i < num_threads; i++)
/// Open synchronous connections (direct, blocking operations)
m_connections[IDX_SYNCH].resize(synch_threads);
for (uint8 i = 0; i < synch_threads; ++i)
{
m_async_connections[i] = new T(m_queue);
m_async_connections[i]->Open(infoString);
++m_connections;
sLog.outSQLDriver("Async database thread pool opened. Worker thread count: %u", num_threads);
T* t = new T();
t->Open(infoString);
m_connections[IDX_SYNCH][i] = t;
++m_connectionCount;
}
/// TODO: Connection details in a struct
m_infoString = infoString;
sLog.outSQLDriver("Databasepool opened succesfuly. %u connections running.", (uint32)m_connectionCount.value());
return true;
}
void Close()
{
sLog.outSQLDriver("Closing down %u connections on this DatabaseWorkerPool", (uint32)m_connections.value());
/// Shuts down worker threads for this connection pool.
sLog.outSQLDriver("Closing down databasepool '%s'.", "missingname");
/// Shuts down delaythreads for this connection pool.
m_queue->queue()->deactivate();
for (uint8 i = 0; i < m_async_connections.size(); i++)
for (uint8 i = 0; i < m_connections[IDX_ASYNC].size(); ++i)
{
m_async_connections[i]->m_worker->wait();
--m_connections;
/// TODO: Better way. probably should flip a boolean and check it on low level code before doing anything on the mysql ctx
/// Now we just wait until m_queue gives the signal to the worker threads to stop
T* t = m_connections[IDX_ASYNC][i];
t->m_worker->wait(); // t->Close(); is called from worker thread
--m_connectionCount;
}
if (m_bundleMask != MYSQL_BUNDLE_NONE)
sLog.outSQLDriver("Asynchronous connections on databasepool '%s' terminated. Proceeding with synchronous connections.", "missingname");
/// Shut down the synchronous connections
for (uint8 i = 0; i < m_connections[IDX_SYNCH].size(); ++i)
{
delete m_bundle_conn;
m_bundle_conn = NULL;
--m_connections;
sLog.outSQLDriver("Closed bundled connection.");
T* t = m_connections[IDX_SYNCH][i];
//while (1)
// if (t->LockIfReady()) -- For some reason deadlocks us
t->Close();
--m_connectionCount;
}
//- MySQL::Thread_End() should be called manually from the aborting calling threads
}
void Init_MySQL_Connection()
{
T* conn = new T();
conn->Open(m_infoString);
// no idea why it doesn't accept sLog here
{
ACE_Guard<ACE_Thread_Mutex> guard(m_connectionMap_mtx);
ConnectionMap::const_iterator itr = m_sync_connections.find(ACE_Based::Thread::current());
#ifdef _DEBUG
if (itr != m_sync_connections.end())
ACE_Singleton<Log, ACE_Thread_Mutex>::instance()->outSQLDriver("Thread ["UI64FMTD"] already started a MySQL connection", (uint64)ACE_Based::Thread::currentId());
#endif
m_sync_connections[ACE_Based::Thread::current()] = conn;
}
ACE_Singleton<Log, ACE_Thread_Mutex>::instance()->outSQLDriver("Core thread with ID ["UI64FMTD"] initializing MySQL connection.",
(uint64)ACE_Based::Thread::currentId());
++m_connections;
}
void End_MySQL_Connection()
{
MySQLConnection* conn;
{
ACE_Guard<ACE_Thread_Mutex> guard(m_connectionMap_mtx);
ConnectionMap::iterator itr = m_sync_connections.find(ACE_Based::Thread::current());
#ifdef _DEBUG
if (itr == m_sync_connections.end())
sLog.outSQLDriver("Thread ["UI64FMTD"] already shut down their MySQL connection.", (uint64)ACE_Based::Thread::currentId());
#endif
conn = itr->second;
m_sync_connections.erase(itr);
}
delete conn;
conn = NULL;
--m_connections;
sLog.outSQLDriver("All connections on databasepool 'missingname' closed.");
}
void Execute(const char* sql)
@@ -191,8 +160,12 @@ class DatabaseWorkerPool
void DirectExecute(const char* sql)
{
if (sql)
GetConnection()->Execute(sql);
if (!sql)
return;
T* t = GetFreeConnection();
t->Execute(sql);
t->Unlock();
}
void DirectPExecute(const char* sql, ...)
@@ -209,9 +182,13 @@ class DatabaseWorkerPool
return DirectExecute(szQuery);
}
QueryResult Query(const char* sql)
QueryResult Query(const char* sql, MySQLConnection* conn = NULL)
{
ResultSet* result = GetConnection()->Query(sql);
if (!conn)
conn = GetFreeConnection();
ResultSet* result = conn->Query(sql);
conn->Unlock();
if (!result || !result->GetRowCount())
return QueryResult(NULL);
@@ -219,6 +196,20 @@ class DatabaseWorkerPool
return QueryResult(result);
}
QueryResult PQuery(const char* sql, MySQLConnection* conn, ...)
{
if (!sql)
return QueryResult(NULL);
va_list ap;
char szQuery[MAX_QUERY_LEN];
va_start(ap, sql);
vsnprintf(szQuery, MAX_QUERY_LEN, sql, ap);
va_end(ap);
return Query(szQuery, conn);
}
QueryResult PQuery(const char* sql, ...)
{
if (!sql)
@@ -303,11 +294,12 @@ class DatabaseWorkerPool
delete[] buf;
}
MySQLThreadBundle GetBundleMask() { return m_bundleMask; }
PreparedQueryResult Query(PreparedStatement* stmt)
{
PreparedResultSet* ret = GetConnection()->Query(stmt);
T* t = GetFreeConnection();
PreparedResultSet* ret = t->Query(stmt);
t->Unlock();
if (!ret || !ret->GetRowCount())
return PreparedQueryResult(NULL);
@@ -316,22 +308,14 @@ class DatabaseWorkerPool
void KeepAlive()
{
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())
itr->second->Ping();
}
if (m_bundle_conn)
m_bundle_conn->Ping();
/// Ping syncrhonous connections
for (uint8 i = 0; i < m_connections[IDX_SYNCH].size(); ++i)
m_connections[IDX_SYNCH][i]->Ping();
/// Assuming all worker threads are free, every worker thread will receive 1 ping operation request
/// If one or more worker threads are busy, the ping operations will not be split evenly, but this doesn't matter
/// as the sole purpose is to prevent connections from idling.
for (size_t i = 0; i < m_async_connections.size(); ++i)
for (size_t i = 0; i < m_connections[IDX_ASYNC].size(); ++i)
Enqueue(new PingOperation);
}
@@ -340,7 +324,11 @@ class DatabaseWorkerPool
{
if (!to || !from || !length)
return 0;
return (mysql_real_escape_string(GetConnection()->GetHandle(), to, from, length));
T* t = GetFreeConnection();
unsigned long ret = mysql_real_escape_string(t->GetHandle(), to, from, length);
t->Unlock();
return ret;
}
void Enqueue(SQLOperation* op)
@@ -348,32 +336,33 @@ class DatabaseWorkerPool
m_queue->enqueue(op);
}
MySQLConnection* GetConnection()
T* GetFreeConnection()
{
MySQLConnection* conn;
ConnectionMap::const_iterator itr;
uint8 i = 0;
size_t num_cons = m_connections[IDX_SYNCH].size();
for (;;) /// Block forever until a connection is free
{
/*! 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())
return itr->second;
T* t = m_connections[IDX_SYNCH][++i % num_cons ];
if (t->LockIfReady()) /// Must be matched with t->Unlock() or you will get deadlocks
return t;
}
/*! Bundled threads */
conn = m_bundle_conn;
ASSERT (conn);
return conn;
// This will be called when Celine Dion learns to sing
return NULL;
}
private:
enum
{
IDX_ASYNC,
IDX_SYNCH,
IDX_SIZE,
};
ACE_Activation_Queue* m_queue; //! Queue shared by async worker threads.
std::vector<T*> 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
T* m_bundle_conn; //! Bundled connection (see Database.ThreadBundleMask config)
AtomicUInt m_connections; //! Counter of MySQL connections;
std::vector< std::vector<T*> > m_connections;
AtomicUInt m_connectionCount; //! Counter of MySQL connections;
std::string m_infoString; //! Infostring that is passed on to child connections.
MySQLThreadBundle m_bundleMask; //! Our configured bundle mask (see enum)
};
#endif

View File

@@ -49,11 +49,20 @@ m_Mysql(NULL)
MySQLConnection::~MySQLConnection()
{
ASSERT (m_Mysql); /// MySQL context must be present at this point
sLog.outSQLDriver("MySQLConnection::~MySQLConnection()");
for (size_t i = 0; i < m_stmts.size(); ++i)
delete m_stmts[i];
MySQL::Thread_End();
mysql_close(m_Mysql);
Unlock(); /// Unlock while we die, how ironic
}
void MySQLConnection::Close()
{
/// Only close us if we're not operating
delete this;
}
bool MySQLConnection::Open(const std::string& infoString)
@@ -163,9 +172,6 @@ bool MySQLConnection::Execute(const char* sql)
return false;
{
// guarded block for thread-safe mySQL request
ACE_Guard<ACE_Thread_Mutex> query_connection_guard(m_Mutex);
#ifdef SQLQUERY_LOG
uint32 _s = getMSTime();
#endif
@@ -193,9 +199,6 @@ bool MySQLConnection::Execute(PreparedStatement* stmt)
uint32 index = stmt->m_index;
{
// guarded block for thread-safe mySQL request
ACE_Guard<ACE_Thread_Mutex> query_connection_guard(m_Mutex);
MySQLPreparedStatement* m_mStmt = GetPreparedStatement(index);
ASSERT(m_mStmt); // Can only be null if preparation failed, server side error or bad query
m_mStmt->m_stmt = stmt; // Cross reference them for debug output
@@ -238,9 +241,6 @@ bool MySQLConnection::_Query(PreparedStatement* stmt, MYSQL_RES **pResult, MYSQL
uint32 index = stmt->m_index;
{
// guarded block for thread-safe mySQL request
ACE_Guard<ACE_Thread_Mutex> query_connection_guard(m_Mutex);
MySQLPreparedStatement* m_mStmt = GetPreparedStatement(index);
ASSERT(m_mStmt); // Can only be null if preparation failed, server side error or bad query
m_mStmt->m_stmt = stmt; // Cross reference them for debug output
@@ -304,8 +304,6 @@ bool MySQLConnection::_Query(const char *sql, MYSQL_RES **pResult, MYSQL_FIELD *
return false;
{
// guarded block for thread-safe mySQL request
ACE_Guard<ACE_Thread_Mutex> query_connection_guard(m_Mutex);
#ifdef SQLQUERY_LOG
uint32 _s = getMSTime();
#endif

View File

@@ -25,10 +25,12 @@
class DatabaseWorker;
class PreparedStatement;
class MySQLPreparedStatement;
class PingOperation;
class MySQLConnection
{
template <class T> friend class DatabaseWorkerPool;
friend class PingOperation;
public:
MySQLConnection(); //! Constructor for synchroneous connections.
@@ -36,6 +38,7 @@ class MySQLConnection
~MySQLConnection();
virtual bool Open(const std::string& infoString); //! Connection details.
void Close();
public:
bool Execute(const char* sql);
@@ -58,6 +61,19 @@ class MySQLConnection
void PrepareStatement(uint32 index, const char* sql);
std::vector<MySQLPreparedStatement*> m_stmts; //! PreparedStatements storage
bool LockIfReady()
{
/// Tries to acquire lock. If lock is acquired by another thread
/// the calling parent will just try another connection
return m_Mutex.tryacquire() != -1;
}
void Unlock()
{
/// Called by parent databasepool. Will let other threads access this connection
m_Mutex.release();
}
private:
ACE_Activation_Queue* m_queue; //! Queue shared with other asynchroneous connections.
DatabaseWorker* m_worker; //! Core worker task.

View File

@@ -163,14 +163,6 @@ public:
sLog.outString ("Starting Remote access listner on port %d on %s", raport, stringip.c_str ());
}
if ((LoginDatabase.GetBundleMask() & MYSQL_BUNDLE_RA))
{
LoginDatabase.Init_MySQL_Connection();
needInit = false;
}
if (needInit)
MySQL::Thread_Init();
}
// Socket Selet time is in microseconds , not miliseconds!!
@@ -184,11 +176,6 @@ public:
h.Select (0, socketSelecttime);
checkping ();
}
if (!needInit)
LoginDatabase.End_MySQL_Connection();
else
MySQL::Thread_End();
}
else
{
@@ -452,8 +439,7 @@ bool Master::_StartDB()
{
sLog.SetLogDB(false);
std::string dbstring;
uint8 num_threads;
int32 mask;
uint8 async_threads, synch_threads;
dbstring = sConfig.GetStringDefault("WorldDatabaseInfo", "");
if (dbstring.empty())
@@ -462,18 +448,18 @@ bool Master::_StartDB()
return false;
}
num_threads = sConfig.GetIntDefault("WorldDatabase.WorkerThreads", 1);
if (num_threads < 1 || num_threads > 32)
async_threads = sConfig.GetIntDefault("WorldDatabase.WorkerThreads", 1);
if (async_threads < 1 || async_threads > 32)
{
sLog.outError("World database: invalid number of worker threads specified. "
"Please pick a value between 1 and 32.");
return false;
}
mask = sConfig.GetIntDefault("WorldDatabase.ThreadBundleMask", MYSQL_BUNDLE_ALL);
synch_threads = sConfig.GetIntDefault("WorldDatabase.SynchThreads", 1);
///- Initialise the world database
if (!WorldDatabase.Open(dbstring, num_threads, MySQLThreadBundle(mask)))
if (!WorldDatabase.Open(dbstring, async_threads, synch_threads))
{
sLog.outError("Cannot connect to world database %s", dbstring.c_str());
return false;
@@ -486,18 +472,18 @@ bool Master::_StartDB()
return false;
}
num_threads = sConfig.GetIntDefault("CharacterDatabase.WorkerThreads", 1);
if (num_threads < 1 || num_threads > 32)
async_threads = sConfig.GetIntDefault("CharacterDatabase.WorkerThreads", 1);
if (async_threads < 1 || async_threads > 32)
{
sLog.outError("Character database: invalid number of worker threads specified. "
"Please pick a value between 1 and 32.");
return false;
}
mask = sConfig.GetIntDefault("CharacterDatabase.ThreadBundleMask", MYSQL_BUNDLE_ALL);
synch_threads = sConfig.GetIntDefault("CharacterDatabase.SynchThreads", 2);
///- Initialise the Character database
if (!CharacterDatabase.Open(dbstring, num_threads, MySQLThreadBundle(mask)))
if (!CharacterDatabase.Open(dbstring, async_threads, synch_threads))
{
sLog.outError("Cannot connect to Character database %s", dbstring.c_str());
return false;
@@ -511,18 +497,18 @@ bool Master::_StartDB()
return false;
}
num_threads = sConfig.GetIntDefault("LoginDatabase.WorkerThreads", 1);
if (num_threads < 1 || num_threads > 32)
async_threads = sConfig.GetIntDefault("LoginDatabase.WorkerThreads", 1);
if (async_threads < 1 || async_threads > 32)
{
sLog.outError("Login database: invalid number of worker threads specified. "
"Please pick a value between 1 and 32.");
return false;
}
mask = sConfig.GetIntDefault("LoginDatabase.ThreadBundleMask", MYSQL_BUNDLE_ALL);
synch_threads = sConfig.GetIntDefault("LoginDatabase.SynchThreads", 1);
///- Initialise the login database
if (!LoginDatabase.Open(dbstring, num_threads, MySQLThreadBundle(mask)))
if (!LoginDatabase.Open(dbstring, async_threads, synch_threads))
{
sLog.outError("Cannot connect to login database %s", dbstring.c_str());
return false;

View File

@@ -43,28 +43,6 @@ extern int m_ServiceStatus;
/// Heartbeat for the World
void WorldRunnable::run()
{
///- Init MySQL threads or connections
bool needInit = true;
if (!(WorldDatabase.GetBundleMask() & MYSQL_BUNDLE_WORLD))
{
WorldDatabase.Init_MySQL_Connection();
needInit = false;
}
if (!(LoginDatabase.GetBundleMask() & MYSQL_BUNDLE_WORLD))
{
LoginDatabase.Init_MySQL_Connection();
needInit = false;
}
if (!(CharacterDatabase.GetBundleMask() & MYSQL_BUNDLE_WORLD))
{
CharacterDatabase.Init_MySQL_Connection();
needInit = false;
}
if (needInit)
MySQL::Thread_Init();
uint32 realCurrTime = 0;
uint32 realPrevTime = getMSTime();
@@ -116,16 +94,4 @@ void WorldRunnable::run()
sMapMgr.UnloadAll(); // unload all grids (including locked in memory)
///- Free MySQL thread resources and deallocate lingering connections
if (!(WorldDatabase.GetBundleMask() & MYSQL_BUNDLE_WORLD))
WorldDatabase.End_MySQL_Connection();
if (!(LoginDatabase.GetBundleMask() & MYSQL_BUNDLE_WORLD))
LoginDatabase.End_MySQL_Connection();
if (!(CharacterDatabase.GetBundleMask() & MYSQL_BUNDLE_WORLD))
CharacterDatabase.End_MySQL_Connection();
if (needInit)
MySQL::Thread_End();
}

View File

@@ -39,25 +39,18 @@
# WorldDatabase.WorkerThreads
# CharacterDatabase.WorkerThreads
# The amount of worker threads spawned to handle
# asynchroneous MySQL statements
# asynchronous (delayed) 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
# LoginDatabase.SynchThreads
# WorldDatabase.SynchThreads
# CharacterDatabase.SynchThreads
# The amount of MySQL connections spawned to handle
# synchronous (blocking) MySQL statements.
# Default: 1, 1, 2
#
# MaxPingTime
# Settings for maximum database-ping interval (minutes between pings)
@@ -79,9 +72,9 @@ 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
LoginDatabase.SynchThreads = 1
WorldDatabase.SynchThreads = 1
CharacterDatabase.SynchThreads = 2
MaxPingTime = 30
WorldServerPort = 8085
BindIP = "0.0.0.0"