aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rwxr-xr-xsrc/server/shared/Database/DatabaseWorkerPool.h170
-rwxr-xr-xsrc/server/shared/Database/MySQLConnection.cpp4
2 files changed, 92 insertions, 82 deletions
diff --git a/src/server/shared/Database/DatabaseWorkerPool.h b/src/server/shared/Database/DatabaseWorkerPool.h
index aef952fab55..5fe31006bb2 100755
--- a/src/server/shared/Database/DatabaseWorkerPool.h
+++ b/src/server/shared/Database/DatabaseWorkerPool.h
@@ -33,17 +33,11 @@
class PingOperation : public SQLOperation
{
- /// Operation for idle delaythreads
+ //! Operation for idle delaythreads
bool Execute()
{
- if (m_conn->LockIfReady())
- {
- m_conn->Ping();
- m_conn->Unlock();
- return true;
- }
-
- return false;
+ m_conn->Ping();
+ return true;
}
};
@@ -53,10 +47,10 @@ class DatabaseWorkerPool
public:
/* Activity state */
DatabaseWorkerPool() :
- m_queue(new ACE_Activation_Queue())
+ _queue(new ACE_Activation_Queue())
{
- memset(m_connectionCount, 0, sizeof(m_connectionCount));
- m_connections.resize(IDX_SIZE);
+ memset(_connectionCount, 0, sizeof(_connectionCount));
+ _connections.resize(IDX_SIZE);
WPFatal (mysql_thread_safe(), "Used MySQL library isn't thread-safe.");
}
@@ -68,66 +62,72 @@ class DatabaseWorkerPool
bool Open(const std::string& infoString, uint8 async_threads, uint8 synch_threads)
{
bool res = true;
- m_connectionInfo = MySQLConnectionInfo(infoString);
+ _connectionInfo = MySQLConnectionInfo(infoString);
- sLog->outSQLDriver("Opening databasepool '%s'. Async threads: %u, synch threads: %u", m_connectionInfo.database.c_str(), async_threads, synch_threads);
+ sLog->outSQLDriver("Opening DatabasePool '%s'. Asynchronous connections: %u, synchronous connections: %u.",
+ GetDatabaseName(), async_threads, synch_threads);
- /// Open asynchronous connections (delayed operations)
- m_connections[IDX_ASYNC].resize(async_threads);
+ //! Open asynchronous connections (delayed operations)
+ _connections[IDX_ASYNC].resize(async_threads);
for (uint8 i = 0; i < async_threads; ++i)
{
- T* t = new T(m_queue, m_connectionInfo);
+ T* t = new T(_queue, _connectionInfo);
res &= t->Open();
- m_connections[IDX_ASYNC][i] = t;
- ++m_connectionCount[IDX_ASYNC];
+ _connections[IDX_ASYNC][i] = t;
+ ++_connectionCount[IDX_ASYNC];
}
- /// Open synchronous connections (direct, blocking operations)
- m_connections[IDX_SYNCH].resize(synch_threads);
+ //! Open synchronous connections (direct, blocking operations)
+ _connections[IDX_SYNCH].resize(synch_threads);
for (uint8 i = 0; i < synch_threads; ++i)
{
- T* t = new T(m_connectionInfo);
+ T* t = new T(_connectionInfo);
res &= t->Open();
- m_connections[IDX_SYNCH][i] = t;
- ++m_connectionCount[IDX_SYNCH];
+ _connections[IDX_SYNCH][i] = t;
+ ++_connectionCount[IDX_SYNCH];
}
- sLog->outSQLDriver("Databasepool opened successfully. %u total connections running.", (m_connectionCount[IDX_SYNCH] + m_connectionCount[IDX_ASYNC]));
+ if (res)
+ sLog->outSQLDriver("DatabasePool '%s' opened successfully. %u total connections running.", GetDatabaseName(),
+ (_connectionCount[IDX_SYNCH] + _connectionCount[IDX_ASYNC]));
+ else
+ sLog->outError("DatabasePool %s NOT opened. There were errors opening the MySQL connections. Check your SQLDriverLogFile "
+ "for specific errors.", GetDatabaseName());
return res;
}
void Close()
{
- sLog->outSQLDriver("Closing down databasepool '%s'.", m_connectionInfo.database.c_str());
+ sLog->outSQLDriver("Closing down DatabasePool '%s'.", GetDatabaseName());
- /// Shuts down delaythreads for this connection pool by underlying deactivate()
- m_queue->queue()->close();
+ //! Shuts down delaythreads for this connection pool by underlying deactivate().
+ //! The next dequeue attempt in the worker thread tasks will result in an error,
+ //! ultimately ending the worker thread task.
+ _queue->queue()->close();
- for (uint8 i = 0; i < m_connectionCount[IDX_ASYNC]; ++i)
+ for (uint8 i = 0; i < _connectionCount[IDX_ASYNC]; ++i)
{
- /// 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* t = _connections[IDX_ASYNC][i];
DatabaseWorker* worker = t->m_worker;
- worker->wait();
+ worker->wait(); //! Block until no more threads are running this task.
delete worker;
- t->Close();
+ t->Close(); //! Closes the actualy MySQL connection.
}
- sLog->outSQLDriver("Asynchronous connections on databasepool '%s' terminated. Proceeding with synchronous connections.", m_connectionInfo.database.c_str());
+ sLog->outSQLDriver("Asynchronous connections on DatabasePool '%s' terminated. Proceeding with synchronous connections.",
+ GetDatabaseName());
- /// Shut down the synchronous connections
- for (uint8 i = 0; i < m_connectionCount[IDX_SYNCH]; ++i)
- {
- T* t = m_connections[IDX_SYNCH][i];
- //while (1)
- // if (t->LockIfReady()) -- For some reason deadlocks us
- t->Close();
- }
+ //! Shut down the synchronous connections
+ //! There's no need for locking the connection, because DatabaseWorkerPool<>::Close
+ //! should only be called after any other thread tasks in the core have exited,
+ //! meaning there can be no concurrent access at this point.
+ for (uint8 i = 0; i < _connectionCount[IDX_SYNCH]; ++i)
+ _connections[IDX_SYNCH][i]->Close();
- delete m_queue;
+ //! Deletes the ACE_Activation_Queue object and its underlying ACE_Message_Queue
+ delete _queue;
- sLog->outSQLDriver("All connections on databasepool %s closed.", m_connectionInfo.database.c_str());
+ sLog->outSQLDriver("All connections on DatabasePool '%s' closed.", GetDatabaseName());
}
/**
@@ -344,20 +344,22 @@ class DatabaseWorkerPool
//! were appended to the transaction will be respected during execution.
void CommitTransaction(SQLTransaction transaction)
{
- if (sLog->GetSQLDriverQueryLogging())
+ #ifdef TRINITY_DEBUG
+ //! Only analyze transaction weaknesses in Debug mode.
+ //! Ideally we catch the faults in Debug mode and then correct them,
+ //! so there's no need to waste these CPU cycles in Release mode.
+ switch (transaction->GetSize())
{
- switch (transaction->GetSize())
- {
- case 0:
- sLog->outSQLDriver("Transaction contains 0 queries. Not executing.");
- return;
- case 1:
- sLog->outSQLDriver("Warning: Transaction only holds 1 query, consider removing Transaction context in code.");
- break;
- default:
- break;
- }
+ case 0:
+ sLog->outSQLDriver("Transaction contains 0 queries. Not executing.");
+ return;
+ case 1:
+ sLog->outSQLDriver("Warning: Transaction only holds 1 query, consider removing Transaction context in code.");
+ break;
+ default:
+ break;
}
+ #endif // TRINITY_DEBUG
Enqueue(new TransactionTask(transaction));
}
@@ -373,9 +375,11 @@ class DatabaseWorkerPool
return;
}
+ //! Handle MySQL Errno 1213 without extending deadlock to the core itself
+ //! TODO: More elegant way
if (con->GetLastError() == 1213)
{
- uint8 loopBreaker = 5; // Handle MySQL Errno 1213 without extending deadlock to the core itself
+ uint8 loopBreaker = 5;
for (uint8 i = 0; i < loopBreaker; ++i)
{
if (con->ExecuteTransaction(transaction))
@@ -383,7 +387,7 @@ class DatabaseWorkerPool
}
}
- // Clean up now.
+ //! Clean up now.
transaction->Cleanup();
con->Unlock();
@@ -414,6 +418,7 @@ class DatabaseWorkerPool
*/
//! Automanaged (internally) pointer to a prepared statement object for usage in upper level code.
+ //! Pointer is deleted in this->Query(PreparedStatement*) or PreparedStatementTask::~PreparedStatementTask.
//! This object is not tied to the prepared statement on the MySQL context yet until execution.
PreparedStatement* GetPreparedStatement(uint32 index)
{
@@ -435,10 +440,10 @@ class DatabaseWorkerPool
//! Keeps all our MySQL connections alive, prevent the server from disconnecting us.
void KeepAlive()
{
- /// Ping synchronous connections
- for (uint8 i = 0; i < m_connectionCount[IDX_SYNCH]; ++i)
+ //! Ping synchronous connections
+ for (uint8 i = 0; i < _connectionCount[IDX_SYNCH]; ++i)
{
- T* t = m_connections[IDX_SYNCH][i];
+ T* t = _connections[IDX_SYNCH][i];
if (t->LockIfReady())
{
t->Ping();
@@ -446,10 +451,10 @@ class DatabaseWorkerPool
}
}
- /// 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_connections[IDX_ASYNC].size(); ++i)
+ //! 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 < _connections[IDX_ASYNC].size(); ++i)
Enqueue(new PingOperation);
}
@@ -459,41 +464,50 @@ class DatabaseWorkerPool
if (!to || !from || !length)
return 0;
- return mysql_real_escape_string(m_connections[IDX_SYNCH][0]->GetHandle(), to, from, length);
+ return mysql_real_escape_string(_connections[IDX_SYNCH][0]->GetHandle(), to, from, length);
}
void Enqueue(SQLOperation* op)
{
- m_queue->enqueue(op);
+ _queue->enqueue(op);
}
+ //! Gets a free connection in the synchronous connection pool.
+ //! Caller MUST call t->Unlock() after touching the MySQL context to prevent deadlocks.
T* GetFreeConnection()
{
uint8 i = 0;
- size_t num_cons = m_connectionCount[IDX_SYNCH];
- for (;;) /// Block forever until a connection is free
+ size_t num_cons = _connectionCount[IDX_SYNCH];
+ //! Block forever until a connection is free
+ for (;;)
{
- T* t = m_connections[IDX_SYNCH][++i % num_cons ];
- if (t->LockIfReady()) /// Must be matched with t->Unlock() or you will get deadlocks
+ T* t = _connections[IDX_SYNCH][++i % num_cons];
+ //! Must be matched with t->Unlock() or you will get deadlocks
+ if (t->LockIfReady())
return t;
}
- // This will be called when Celine Dion learns to sing
+ //! This will be called when Celine Dion learns to sing
return NULL;
}
+ char const* GetDatabaseName() const
+ {
+ return _connectionInfo.database.c_str();
+ }
+
private:
- enum
+ enum _internalIndex
{
IDX_ASYNC,
IDX_SYNCH,
IDX_SIZE,
};
- ACE_Activation_Queue* m_queue; //! Queue shared by async worker threads.
- std::vector< std::vector<T*> > m_connections;
- uint32 m_connectionCount[2]; //! Counter of MySQL connections;
- MySQLConnectionInfo m_connectionInfo;
+ ACE_Activation_Queue* _queue; //! Queue shared by async worker threads.
+ std::vector< std::vector<T*> > _connections;
+ uint32 _connectionCount[2]; //! Counter of MySQL connections;
+ MySQLConnectionInfo _connectionInfo;
};
#endif
diff --git a/src/server/shared/Database/MySQLConnection.cpp b/src/server/shared/Database/MySQLConnection.cpp
index f686db4c199..7fb4a4f7025 100755
--- a/src/server/shared/Database/MySQLConnection.cpp
+++ b/src/server/shared/Database/MySQLConnection.cpp
@@ -58,17 +58,13 @@ 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];
for (PreparedStatementMap::const_iterator itr = m_queries.begin(); itr != m_queries.end(); ++itr)
- {
free((void *)m_queries[itr->first].first);
- }
mysql_close(m_Mysql);
- Unlock(); /// Unlock while we die, how ironic
}
void MySQLConnection::Close()