diff options
author | Machiavelli <machiavelli.trinity@gmail.com> | 2011-01-13 20:07:09 +0100 |
---|---|---|
committer | Machiavelli <machiavelli.trinity@gmail.com> | 2011-01-13 20:07:09 +0100 |
commit | cf9250c29f4e66f6a8fe6d14ace798a4252ce59b (patch) | |
tree | 00e9983260a4c20f7ffef1e2a2b05ba30d8b4772 /src | |
parent | 8d59953f9372c6876e0cd8078b44de6893082cbe (diff) |
Core/DBLayer:
- Implement DatabaseWorkerPool::DirectCommitTransaction for synchronous transaction execution (as opposed to asynchronous/enqueued).
- Add MySQL errno 1213 "Deadlock found when trying to get lock; try restarting transaction" handler. If 1213 is called the core will retry to directly execute the transaction a maximum of 5 times.
Diffstat (limited to 'src')
-rwxr-xr-x | src/server/shared/Database/DatabaseWorkerPool.h | 24 | ||||
-rwxr-xr-x | src/server/shared/Database/MySQLConnection.cpp | 49 | ||||
-rwxr-xr-x | src/server/shared/Database/MySQLConnection.h | 4 | ||||
-rwxr-xr-x | src/server/shared/Database/Transaction.cpp | 47 | ||||
-rwxr-xr-x | src/server/shared/Database/Transaction.h | 4 |
5 files changed, 89 insertions, 39 deletions
diff --git a/src/server/shared/Database/DatabaseWorkerPool.h b/src/server/shared/Database/DatabaseWorkerPool.h index 5c7ebfd796e..957d93d449b 100755 --- a/src/server/shared/Database/DatabaseWorkerPool.h +++ b/src/server/shared/Database/DatabaseWorkerPool.h @@ -353,6 +353,30 @@ class DatabaseWorkerPool Enqueue(new TransactionTask(transaction)); } + //! Directly executes a collection of one-way SQL operations (can be both adhoc and prepared). The order in which these operations + //! were appended to the transaction will be respected during execution. + void DirectCommitTransaction(SQLTransaction& transaction) + { + MySQLConnection* con = GetFreeConnection(); + if (con->ExecuteTransaction(transaction)) + { + con->Unlock(); // OK, operation succesful + return; + } + + if (con->GetLastError() == 1213) + { + uint8 loopBreaker = 5; // Handle MySQL Errno 1213 without extending deadlock to the core itself + for (uint8 i = 0; i < loopBreaker; ++i) + { + if (con->ExecuteTransaction(transaction)) + break; + } + } + + con->Unlock(); + } + //! Method used to execute prepared statements in a diverse context. //! Will be wrapped in a transaction if valid object is present, otherwise executed standalone. void ExecuteOrAppend(SQLTransaction& trans, PreparedStatement* stmt) diff --git a/src/server/shared/Database/MySQLConnection.cpp b/src/server/shared/Database/MySQLConnection.cpp index 2a07fad7a9b..832a801f94b 100755 --- a/src/server/shared/Database/MySQLConnection.cpp +++ b/src/server/shared/Database/MySQLConnection.cpp @@ -369,6 +369,52 @@ void MySQLConnection::CommitTransaction() Execute("COMMIT"); } +bool MySQLConnection::ExecuteTransaction(SQLTransaction& transaction) +{ + std::queue<SQLElementData> &queries = transaction->m_queries; + if (queries.empty()) + return false; + + BeginTransaction(); + while (!queries.empty()) + { + SQLElementData data = queries.front(); + switch (data.type) + { + case SQL_ELEMENT_PREPARED: + { + PreparedStatement* stmt = data.element.stmt; + ASSERT(stmt); + if (!Execute(stmt)) + { + sLog->outSQLDriver("[Warning] Transaction aborted. %u queries not executed.", (uint32)queries.size()); + RollbackTransaction(); + return false; + } + delete data.element.stmt; + } + break; + case SQL_ELEMENT_RAW: + { + const char* sql = data.element.query; + ASSERT(sql); + if (!Execute(sql)) + { + sLog->outSQLDriver("[Warning] Transaction aborted. %u queries not executed.", (uint32)queries.size()); + RollbackTransaction(); + return false; + } + free((void*)const_cast<char*>(sql)); + } + break; + } + queries.pop(); + } + + CommitTransaction(); + return true; +} + MySQLPreparedStatement* MySQLConnection::GetPreparedStatement(uint32 index) { ASSERT(index < m_stmts.size()); @@ -462,6 +508,9 @@ bool MySQLConnection::_HandleMySQLErrno(uint32 errNo) return _HandleMySQLErrno(lErrno); // Call self (recursive) } + case 1213: // "Deadlock found when trying to get lock; try restarting transaction" + return true; // Implemented in TransactionTask::Execute and DatabaseWorkerPool<T>::DirectCommitTransaction + // Query related errors - skip query case 1058: // "Column count doesn't match value count" case 1062: // "Duplicate entry '%s' for key '%d'" diff --git a/src/server/shared/Database/MySQLConnection.h b/src/server/shared/Database/MySQLConnection.h index f96284de5f8..9cc57000171 100755 --- a/src/server/shared/Database/MySQLConnection.h +++ b/src/server/shared/Database/MySQLConnection.h @@ -18,6 +18,7 @@ #include <ace/Activation_Queue.h> #include "DatabaseWorkerPool.h" +#include "Transaction.h" #include "Util.h" #ifndef _MYSQLCONNECTION_H @@ -91,10 +92,13 @@ class MySQLConnection void BeginTransaction(); void RollbackTransaction(); void CommitTransaction(); + bool ExecuteTransaction(SQLTransaction& transaction); operator bool () const { return m_Mysql != NULL; } void Ping() { mysql_ping(m_Mysql); } + uint32 GetLastError() { return mysql_errno(m_Mysql); } + protected: bool LockIfReady() { diff --git a/src/server/shared/Database/Transaction.cpp b/src/server/shared/Database/Transaction.cpp index b09415c6c7c..8604dfc609c 100755 --- a/src/server/shared/Database/Transaction.cpp +++ b/src/server/shared/Database/Transaction.cpp @@ -67,45 +67,16 @@ void Transaction::Cleanup() bool TransactionTask::Execute() { - std::queue<SQLElementData> &queries = m_trans->m_queries; - if (queries.empty()) - return false; + if (m_conn->ExecuteTransaction(m_trans)) + return true; - m_conn->BeginTransaction(); - while (!queries.empty()) + if (m_conn->GetLastError() == 1213) { - SQLElementData data = queries.front(); - switch (data.type) - { - case SQL_ELEMENT_PREPARED: - { - PreparedStatement* stmt = data.element.stmt; - ASSERT(stmt); - if (!m_conn->Execute(stmt)) - { - sLog->outSQLDriver("[Warning] Transaction aborted. %u queries not executed.", (uint32)queries.size()); - m_conn->RollbackTransaction(); - return false; - } - delete data.element.stmt; - } - break; - case SQL_ELEMENT_RAW: - { - const char* sql = data.element.query; - ASSERT(sql); - if (!m_conn->Execute(sql)) - { - sLog->outSQLDriver("[Warning] Transaction aborted. %u queries not executed.", (uint32)queries.size()); - m_conn->RollbackTransaction(); - return false; - } - free((void*)const_cast<char*>(sql)); - } - break; - } - queries.pop(); + uint8 loopBreaker = 5; // Handle MySQL Errno 1213 without extending deadlock to the core itself + for (uint8 i = 0; i < loopBreaker; ++i) + if (m_conn->ExecuteTransaction(m_trans)) + return true; } - m_conn->CommitTransaction(); - return true; + + return false; } diff --git a/src/server/shared/Database/Transaction.h b/src/server/shared/Database/Transaction.h index 46e13a84a14..da603b8cf50 100755 --- a/src/server/shared/Database/Transaction.h +++ b/src/server/shared/Database/Transaction.h @@ -27,6 +27,8 @@ class PreparedStatement; class Transaction { friend class TransactionTask; + friend class MySQLConnection; + public: Transaction() {} ~Transaction() { Cleanup(); } @@ -49,7 +51,7 @@ class TransactionTask : public SQLOperation { template <class T> friend class DatabaseWorkerPool; friend class DatabaseWorker; - + public: TransactionTask(SQLTransaction trans) : m_trans(trans) {} ; ~TransactionTask(){}; |