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
34
35//- Append a raw ad-hoc query to the transaction
36void TransactionBase::Append(char const* sql)
37{
38 ASSERT(sql);
39 m_queries.emplace_back(std::in_place_type<std::string>, sql);
40}
41
42//- Append a prepared statement to the transaction
44{
45 ASSERT(stmt);
46 m_queries.emplace_back(std::in_place_type<std::unique_ptr<PreparedStatementBase>>, stmt);
47}
48
50{
51 // This might be called by explicit calls to Cleanup or by the auto-destructor
52 if (_cleanedUp)
53 return;
54
55 m_queries.clear();
56 _cleanedUp = true;
57}
58
59bool TransactionTask::Execute(MySQLConnection* conn, std::shared_ptr<TransactionBase> trans)
60{
61 int errorCode = TryExecute(conn, trans);
62 if (!errorCode)
63 return true;
64
65 if (errorCode == ER_LOCK_DEADLOCK)
66 {
67 std::string threadId = []()
68 {
69 // wrapped in lambda to fix false positive analysis warning C26115
70 std::ostringstream threadIdStream;
71 threadIdStream << std::this_thread::get_id();
72 return threadIdStream.str();
73 }();
74
75 // Make sure only 1 async thread retries a transaction so they don't keep dead-locking each other
76 std::lock_guard<std::mutex> lock(_deadlockLock);
77
78 for (uint32 loopDuration = 0, startMSTime = getMSTime(); loopDuration <= DEADLOCK_MAX_RETRY_TIME_MS; loopDuration = GetMSTimeDiffToNow(startMSTime))
79 {
80 if (!TryExecute(conn, trans))
81 return true;
82
83 TC_LOG_WARN("sql.sql", "Deadlocked SQL Transaction, retrying. Loop timer: {} ms, Thread Id: {}", loopDuration, threadId);
84 }
85
86 TC_LOG_ERROR("sql.sql", "Fatal deadlocked SQL Transaction, it will not be retried anymore. Thread Id: {}", threadId);
87 }
88
89 // Clean up now.
90 trans->Cleanup();
91
92 return false;
93}
94
95int TransactionTask::TryExecute(MySQLConnection* conn, std::shared_ptr<TransactionBase> trans)
96{
97 return conn->ExecuteTransaction(trans);
98}
99
101{
102 if (m_future.valid() && m_future.wait_for(std::chrono::seconds(0)) == std::future_status::ready)
103 {
104 m_callback(m_future.get());
105 return true;
106 }
107
108 return false;
109}
uint32_t uint32
Definition: Define.h:142
#define ASSERT
Definition: Errors.h:68
#define TC_LOG_ERROR(filterType__, message__,...)
Definition: Log.h:188
#define TC_LOG_WARN(filterType__, message__,...)
Definition: Log.h:185
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:77
void AppendPreparedStatement(PreparedStatementBase *statement)
Definition: Transaction.cpp:43
void Append(char const *sql)
Definition: Transaction.cpp:36
std::future< bool > m_future
Definition: Transaction.h:121
std::function< void(bool)> m_callback
Definition: Transaction.h:122
static int TryExecute(MySQLConnection *conn, std::shared_ptr< TransactionBase > trans)
Definition: Transaction.cpp:95
static std::mutex _deadlockLock
Definition: Transaction.h:103
static bool Execute(MySQLConnection *conn, std::shared_ptr< TransactionBase > trans)
Definition: Transaction.cpp:59