TrinityCore
Transaction.cpp
Go to the documentation of this file.
1/*
2 * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation; either version 2 of the License, or (at your
7 * option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#include "Transaction.h"
19#include "Errors.h"
20#include "Log.h"
21#include "MySQLConnection.h"
22#include "PreparedStatement.h"
23#include "Timer.h"
24#include <mysqld_error.h>
25#include <sstream>
26#include <thread>
27#include <cstring>
28
30
31#define DEADLOCK_MAX_RETRY_TIME_MS 60000
32
33//- Append a raw ad-hoc query to the transaction
34void TransactionBase::Append(char const* sql)
35{
36 ASSERT(sql);
37 m_queries.emplace_back(std::in_place_type<std::string>, sql);
38}
39
40//- Append a prepared statement to the transaction
42{
43 ASSERT(stmt);
44 m_queries.emplace_back(std::in_place_type<std::unique_ptr<PreparedStatementBase>>, stmt);
45}
46
48{
49 // This might be called by explicit calls to Cleanup or by the auto-destructor
50 if (_cleanedUp)
51 return;
52
53 m_queries.clear();
54 _cleanedUp = true;
55}
56
57bool TransactionTask::Execute(MySQLConnection* conn, std::shared_ptr<TransactionBase> trans)
58{
59 int errorCode = TryExecute(conn, trans);
60 if (!errorCode)
61 return true;
62
63 if (errorCode == ER_LOCK_DEADLOCK)
64 {
65 std::string threadId = []()
66 {
67 // wrapped in lambda to fix false positive analysis warning C26115
68 std::ostringstream threadIdStream;
69 threadIdStream << std::this_thread::get_id();
70 return threadIdStream.str();
71 }();
72
73 // Make sure only 1 async thread retries a transaction so they don't keep dead-locking each other
74 std::lock_guard<std::mutex> lock(_deadlockLock);
75
76 for (uint32 loopDuration = 0, startMSTime = getMSTime(); loopDuration <= DEADLOCK_MAX_RETRY_TIME_MS; loopDuration = GetMSTimeDiffToNow(startMSTime))
77 {
78 if (!TryExecute(conn, trans))
79 return true;
80
81 TC_LOG_WARN("sql.sql", "Deadlocked SQL Transaction, retrying. Loop timer: {} ms, Thread Id: {}", loopDuration, threadId);
82 }
83
84 TC_LOG_ERROR("sql.sql", "Fatal deadlocked SQL Transaction, it will not be retried anymore. Thread Id: {}", threadId);
85 }
86
87 // Clean up now.
88 trans->Cleanup();
89
90 return false;
91}
92
93int TransactionTask::TryExecute(MySQLConnection* conn, std::shared_ptr<TransactionBase> trans)
94{
95 return conn->ExecuteTransaction(trans);
96}
97
99{
100 if (m_future.valid() && m_future.wait_for(std::chrono::seconds(0)) == std::future_status::ready)
101 {
102 m_callback(m_future.get());
103 return true;
104 }
105
106 return false;
107}
uint32_t uint32
Definition: Define.h:142
#define ASSERT
Definition: Errors.h:68
#define TC_LOG_WARN(filterType__,...)
Definition: Log.h:162
#define TC_LOG_ERROR(filterType__,...)
Definition: Log.h:165
uint32 GetMSTimeDiffToNow(uint32 oldMSTime)
Definition: Timer.h:57
uint32 getMSTime()
Definition: Timer.h:33
#define DEADLOCK_MAX_RETRY_TIME_MS
Definition: Transaction.cpp:31
int ExecuteTransaction(std::shared_ptr< TransactionBase > transaction)
std::vector< TransactionData > m_queries
Definition: Transaction.h:71
void AppendPreparedStatement(PreparedStatementBase *statement)
Definition: Transaction.cpp:41
void Append(char const *sql)
Definition: Transaction.cpp:34
TransactionFuture m_future
Definition: Transaction.h:115
std::function< void(bool)> m_callback
Definition: Transaction.h:116
static int TryExecute(MySQLConnection *conn, std::shared_ptr< TransactionBase > trans)
Definition: Transaction.cpp:93
static std::mutex _deadlockLock
Definition: Transaction.h:97
static bool Execute(MySQLConnection *conn, std::shared_ptr< TransactionBase > trans)
Definition: Transaction.cpp:57