diff --git a/src/common/Utilities/AsyncCallbackProcessor.h b/src/common/Utilities/AsyncCallbackProcessor.h new file mode 100644 index 00000000000..76781f49425 --- /dev/null +++ b/src/common/Utilities/AsyncCallbackProcessor.h @@ -0,0 +1,63 @@ +/* + * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#ifndef AsyncCallbackProcessor_h__ +#define AsyncCallbackProcessor_h__ + +#include "Define.h" +#include +#include + +//template +//concept AsyncCallback = requires(T t) { { t.InvokeIfReady() } -> std::convertible_to }; + +template // requires AsyncCallback +class AsyncCallbackProcessor +{ +public: + AsyncCallbackProcessor() = default; + ~AsyncCallbackProcessor() = default; + + T& AddCallback(T&& query) + { + _callbacks.emplace_back(std::move(query)); + return _callbacks.back(); + } + + void ProcessReadyCallbacks() + { + if (_callbacks.empty()) + return; + + std::vector updateCallbacks{ std::move(_callbacks) }; + + updateCallbacks.erase(std::remove_if(updateCallbacks.begin(), updateCallbacks.end(), [](T& callback) + { + return callback.InvokeIfReady(); + }), updateCallbacks.end()); + + _callbacks.insert(_callbacks.end(), std::make_move_iterator(updateCallbacks.begin()), std::make_move_iterator(updateCallbacks.end())); + } + +private: + AsyncCallbackProcessor(AsyncCallbackProcessor const&) = delete; + AsyncCallbackProcessor& operator=(AsyncCallbackProcessor const&) = delete; + + std::vector _callbacks; +}; + +#endif // AsyncCallbackProcessor_h__ diff --git a/src/server/bnetserver/Server/Session.cpp b/src/server/bnetserver/Server/Session.cpp index 8a619a80263..d2a8dae7e26 100644 --- a/src/server/bnetserver/Server/Session.cpp +++ b/src/server/bnetserver/Server/Session.cpp @@ -199,7 +199,7 @@ void Battlenet::Session::HandleLogonRequest(Authentication::LogonRequest const& LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_ACCOUNT_INFO); stmt->setString(0, login); - _queryProcessor.AddQuery(LoginDatabase.AsyncQuery(stmt).WithPreparedCallback(std::bind(&Battlenet::Session::HandleLogonRequestCallback, this, std::placeholders::_1))); + _queryProcessor.AddCallback(LoginDatabase.AsyncQuery(stmt).WithPreparedCallback(std::bind(&Battlenet::Session::HandleLogonRequestCallback, this, std::placeholders::_1))); } void Battlenet::Session::HandleLogonRequestCallback(PreparedQueryResult result) @@ -338,7 +338,7 @@ void Battlenet::Session::HandleResumeRequest(Authentication::ResumeRequest const stmt->setString(0, login); stmt->setString(1, resumeRequest.GameAccountName); - _queryProcessor.AddQuery(LoginDatabase.AsyncQuery(stmt).WithPreparedCallback(std::bind(&Battlenet::Session::HandleResumeRequestCallback, this, std::placeholders::_1))); + _queryProcessor.AddCallback(LoginDatabase.AsyncQuery(stmt).WithPreparedCallback(std::bind(&Battlenet::Session::HandleResumeRequestCallback, this, std::placeholders::_1))); } void Battlenet::Session::HandleResumeRequestCallback(PreparedQueryResult result) @@ -437,7 +437,7 @@ void Battlenet::Session::HandleListSubscribeRequest(WoWRealm::ListSubscribeReque LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_CHARACTER_COUNTS); stmt->setUInt32(0, _gameAccountInfo->Id); - _queryProcessor.AddQuery(LoginDatabase.AsyncQuery(stmt).WithPreparedCallback(std::bind(&Battlenet::Session::HandleListSubscribeRequestCallback, this, std::placeholders::_1))); + _queryProcessor.AddCallback(LoginDatabase.AsyncQuery(stmt).WithPreparedCallback(std::bind(&Battlenet::Session::HandleListSubscribeRequestCallback, this, std::placeholders::_1))); } void Battlenet::Session::HandleListSubscribeRequestCallback(PreparedQueryResult result) @@ -609,7 +609,7 @@ void Battlenet::Session::Start() LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_IP_INFO); stmt->setString(0, ip_address); - _queryProcessor.AddQuery(LoginDatabase.AsyncQuery(stmt).WithPreparedCallback(std::bind(&Battlenet::Session::CheckIpCallback, this, std::placeholders::_1))); + _queryProcessor.AddCallback(LoginDatabase.AsyncQuery(stmt).WithPreparedCallback(std::bind(&Battlenet::Session::CheckIpCallback, this, std::placeholders::_1))); } void Battlenet::Session::CheckIpCallback(PreparedQueryResult result) @@ -671,7 +671,7 @@ bool Battlenet::Session::Update() if (!BattlenetSocket::Update()) return false; - _queryProcessor.ProcessReadyQueries(); + _queryProcessor.ProcessReadyCallbacks(); return true; } diff --git a/src/server/bnetserver/Server/Session.h b/src/server/bnetserver/Server/Session.h index f42c15948c5..e489208ee6c 100644 --- a/src/server/bnetserver/Server/Session.h +++ b/src/server/bnetserver/Server/Session.h @@ -18,12 +18,12 @@ #ifndef Session_h__ #define Session_h__ +#include "AsyncCallbackProcessor.h" #include "Packets.h" #include "BattlenetPacketCrypt.h" #include "Socket.h" #include "BigNumber.h" #include "QueryResult.h" -#include "QueryCallbackProcessor.h" #include "MPSCQueue.h" #include #include diff --git a/src/server/database/Database/DatabaseEnvFwd.h b/src/server/database/Database/DatabaseEnvFwd.h index b743c88506d..e981be5c026 100644 --- a/src/server/database/Database/DatabaseEnvFwd.h +++ b/src/server/database/Database/DatabaseEnvFwd.h @@ -24,9 +24,9 @@ class Field; class ResultSet; -typedef std::shared_ptr QueryResult; -typedef std::future QueryResultFuture; -typedef std::promise QueryResultPromise; +using QueryResult = std::shared_ptr; +using QueryResultFuture = std::future; +using QueryResultPromise = std::promise; class CharacterDatabaseConnection; class HotfixDatabaseConnection; @@ -44,17 +44,27 @@ using LoginDatabasePreparedStatement = PreparedStatement; class PreparedResultSet; -typedef std::shared_ptr PreparedQueryResult; -typedef std::future PreparedQueryResultFuture; -typedef std::promise PreparedQueryResultPromise; +using PreparedQueryResult = std::shared_ptr; +using PreparedQueryResultFuture = std::future; +using PreparedQueryResultPromise = std::promise; class QueryCallback; +template +class AsyncCallbackProcessor; + +using QueryCallbackProcessor = AsyncCallbackProcessor; + class TransactionBase; +using TransactionFuture = std::future; +using TransactionPromise = std::promise; + template class Transaction; +class TransactionCallback; + template using SQLTransaction = std::shared_ptr>; @@ -64,8 +74,8 @@ using LoginDatabaseTransaction = SQLTransaction; using WorldDatabaseTransaction = SQLTransaction; class SQLQueryHolderBase; -typedef std::future QueryResultHolderFuture; -typedef std::promise QueryResultHolderPromise; +using QueryResultHolderFuture = std::future; +using QueryResultHolderPromise = std::promise; template class SQLQueryHolder; diff --git a/src/server/database/Database/DatabaseWorkerPool.cpp b/src/server/database/Database/DatabaseWorkerPool.cpp index d909949c12c..f701a7c527b 100644 --- a/src/server/database/Database/DatabaseWorkerPool.cpp +++ b/src/server/database/Database/DatabaseWorkerPool.cpp @@ -261,6 +261,32 @@ void DatabaseWorkerPool::CommitTransaction(SQLTransaction transaction) Enqueue(new TransactionTask(transaction)); } +template +TransactionCallback DatabaseWorkerPool::AsyncCommitTransaction(SQLTransaction transaction) +{ +#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()) + { + case 0: + TC_LOG_DEBUG("sql.driver", "Transaction contains 0 queries. Not executing."); + return; + case 1: + TC_LOG_DEBUG("sql.driver", "Warning: Transaction only holds 1 query, consider removing Transaction context in code."); + break; + default: + break; + } +#endif // TRINITY_DEBUG + + TransactionWithResultTask* task = new TransactionWithResultTask(transaction); + TransactionFuture result = task->GetFuture(); + Enqueue(task); + return TransactionCallback(std::move(result)); +} + template void DatabaseWorkerPool::DirectCommitTransaction(SQLTransaction& transaction) { diff --git a/src/server/database/Database/DatabaseWorkerPool.h b/src/server/database/Database/DatabaseWorkerPool.h index 8824dc38d85..f72817c3a8f 100644 --- a/src/server/database/Database/DatabaseWorkerPool.h +++ b/src/server/database/Database/DatabaseWorkerPool.h @@ -173,6 +173,10 @@ class DatabaseWorkerPool //! were appended to the transaction will be respected during execution. void CommitTransaction(SQLTransaction transaction); + //! Enqueues 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. + TransactionCallback AsyncCommitTransaction(SQLTransaction 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); diff --git a/src/server/database/Database/QueryCallback.cpp b/src/server/database/Database/QueryCallback.cpp index 65b52ff7627..02365a76fe7 100644 --- a/src/server/database/Database/QueryCallback.cpp +++ b/src/server/database/Database/QueryCallback.cpp @@ -175,7 +175,7 @@ void QueryCallback::SetNextQuery(QueryCallback&& next) MoveFrom(this, std::move(next)); } -QueryCallback::Status QueryCallback::InvokeIfReady() +bool QueryCallback::InvokeIfReady() { QueryCallbackData& callback = _callbacks.front(); auto checkStateAndReturnCompletion = [this]() @@ -185,15 +185,15 @@ QueryCallback::Status QueryCallback::InvokeIfReady() if (_callbacks.empty()) { ASSERT(!hasNext); - return Completed; + return true; } // abort chain if (!hasNext) - return Completed; + return true; ASSERT(_isPrepared == _callbacks.front()._isPrepared); - return NextStep; + return false; }; if (!_isPrepared) @@ -217,5 +217,5 @@ QueryCallback::Status QueryCallback::InvokeIfReady() } } - return NotReady; + return false; } diff --git a/src/server/database/Database/QueryCallback.h b/src/server/database/Database/QueryCallback.h index 1d7e835e999..6cc315964b7 100644 --- a/src/server/database/Database/QueryCallback.h +++ b/src/server/database/Database/QueryCallback.h @@ -44,14 +44,8 @@ public: // Moves std::future from next to this object void SetNextQuery(QueryCallback&& next); - enum Status - { - NotReady, - NextStep, - Completed - }; - - Status InvokeIfReady(); + // returns true when completed + bool InvokeIfReady(); private: QueryCallback(QueryCallback const& right) = delete; diff --git a/src/server/database/Database/QueryCallbackProcessor.cpp b/src/server/database/Database/QueryCallbackProcessor.cpp deleted file mode 100644 index 546a6d17c04..00000000000 --- a/src/server/database/Database/QueryCallbackProcessor.cpp +++ /dev/null @@ -1,48 +0,0 @@ -/* - * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#include "QueryCallbackProcessor.h" -#include "QueryCallback.h" -#include - -QueryCallbackProcessor::QueryCallbackProcessor() -{ -} - -QueryCallbackProcessor::~QueryCallbackProcessor() -{ -} - -void QueryCallbackProcessor::AddQuery(QueryCallback&& query) -{ - _callbacks.emplace_back(std::move(query)); -} - -void QueryCallbackProcessor::ProcessReadyQueries() -{ - if (_callbacks.empty()) - return; - - std::vector updateCallbacks{ std::move(_callbacks) }; - - updateCallbacks.erase(std::remove_if(updateCallbacks.begin(), updateCallbacks.end(), [](QueryCallback& callback) - { - return callback.InvokeIfReady() == QueryCallback::Completed; - }), updateCallbacks.end()); - - _callbacks.insert(_callbacks.end(), std::make_move_iterator(updateCallbacks.begin()), std::make_move_iterator(updateCallbacks.end())); -} diff --git a/src/server/database/Database/QueryCallbackProcessor.h b/src/server/database/Database/QueryCallbackProcessor.h deleted file mode 100644 index 85596e90092..00000000000 --- a/src/server/database/Database/QueryCallbackProcessor.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#ifndef QueryCallbackProcessor_h__ -#define QueryCallbackProcessor_h__ - -#include "Define.h" -#include - -class QueryCallback; - -class TC_DATABASE_API QueryCallbackProcessor -{ -public: - QueryCallbackProcessor(); - ~QueryCallbackProcessor(); - - void AddQuery(QueryCallback&& query); - void ProcessReadyQueries(); - -private: - QueryCallbackProcessor(QueryCallbackProcessor const&) = delete; - QueryCallbackProcessor& operator=(QueryCallbackProcessor const&) = delete; - - std::vector _callbacks; -}; - -#endif // QueryCallbackProcessor_h__ diff --git a/src/server/database/Database/Transaction.cpp b/src/server/database/Database/Transaction.cpp index e114808ddf0..afa107f31c7 100644 --- a/src/server/database/Database/Transaction.cpp +++ b/src/server/database/Database/Transaction.cpp @@ -70,7 +70,7 @@ void TransactionBase::Cleanup() bool TransactionTask::Execute() { - int errorCode = m_conn->ExecuteTransaction(m_trans); + int errorCode = TryExecute(); if (!errorCode) return true; @@ -85,7 +85,7 @@ bool TransactionTask::Execute() for (uint32 loopDuration = 0, startMSTime = getMSTime(); loopDuration <= DEADLOCK_MAX_RETRY_TIME_MS; loopDuration = GetMSTimeDiffToNow(startMSTime)) { - if (!m_conn->ExecuteTransaction(m_trans)) + if (!TryExecute()) return true; TC_LOG_WARN("sql.sql", "Deadlocked SQL Transaction, retrying. Loop timer: %u ms, Thread Id: %s", loopDuration, threadId.c_str()); @@ -95,7 +95,60 @@ bool TransactionTask::Execute() } // Clean up now. - m_trans->Cleanup(); + CleanupOnFailure(); return false; } + +int TransactionTask::TryExecute() +{ + return m_conn->ExecuteTransaction(m_trans); +} + +void TransactionTask::CleanupOnFailure() +{ + m_trans->Cleanup(); +} + +bool TransactionWithResultTask::Execute() +{ + int errorCode = TryExecute(); + if (!errorCode) + { + m_result.set_value(true); + return true; + } + + if (errorCode == ER_LOCK_DEADLOCK) + { + // Make sure only 1 async thread retries a transaction so they don't keep dead-locking each other + std::lock_guard lock(_deadlockLock); + uint8 loopBreaker = 5; // Handle MySQL Errno 1213 without extending deadlock to the core itself + for (uint8 i = 0; i < loopBreaker; ++i) + { + if (!TryExecute()) + { + m_result.set_value(true); + return true; + } + } + } + + // Clean up now. + CleanupOnFailure(); + m_result.set_value(false); + + return false; +} + +bool TransactionCallback::InvokeIfReady() +{ + if (m_future.valid() && m_future.wait_for(std::chrono::seconds(0)) == std::future_status::ready) + { + m_callback(m_future.get()); + return true; + } + + return false; +} + diff --git a/src/server/database/Database/Transaction.h b/src/server/database/Database/Transaction.h index dac9880d53b..a8e3f511f3d 100644 --- a/src/server/database/Database/Transaction.h +++ b/src/server/database/Database/Transaction.h @@ -22,6 +22,7 @@ #include "DatabaseEnvFwd.h" #include "SQLOperation.h" #include "StringFormat.h" +#include #include #include @@ -73,6 +74,7 @@ class TC_DATABASE_API TransactionTask : public SQLOperation { template friend class DatabaseWorkerPool; friend class DatabaseWorker; + friend class TransactionCallback; public: TransactionTask(std::shared_ptr trans) : m_trans(trans) { } @@ -80,9 +82,43 @@ class TC_DATABASE_API TransactionTask : public SQLOperation protected: bool Execute() override; + int TryExecute(); + void CleanupOnFailure(); std::shared_ptr m_trans; static std::mutex _deadlockLock; }; +class TC_DATABASE_API TransactionWithResultTask : public TransactionTask +{ +public: + TransactionWithResultTask(std::shared_ptr trans) : TransactionTask(trans) { } + + TransactionFuture GetFuture() { return m_result.get_future(); } + +protected: + bool Execute() override; + + TransactionPromise m_result; +}; + +class TC_DATABASE_API TransactionCallback +{ +public: + TransactionCallback(TransactionFuture&& future) : m_future(std::move(future)) { } + TransactionCallback(TransactionCallback&&) = default; + + TransactionCallback& operator=(TransactionCallback&&) = default; + + void AfterComplete(std::function callback) & + { + m_callback = std::move(callback); + } + + bool InvokeIfReady(); + + TransactionFuture m_future; + std::function m_callback; +}; + #endif diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 4f7b8836f3b..c1290dde422 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -27172,7 +27172,7 @@ void Player::ActivateSpec(uint8 spec) stmt->setUInt8(1, GetActiveSpec()); WorldSession* mySess = GetSession(); - mySess->GetQueryProcessor().AddQuery(CharacterDatabase.AsyncQuery(stmt) + mySess->GetQueryProcessor().AddCallback(CharacterDatabase.AsyncQuery(stmt) .WithPreparedCallback([mySess](PreparedQueryResult result) { // safe callback, we can't pass this pointer directly diff --git a/src/server/game/Handlers/CharacterHandler.cpp b/src/server/game/Handlers/CharacterHandler.cpp index e0c8002c522..ee2da03a323 100644 --- a/src/server/game/Handlers/CharacterHandler.cpp +++ b/src/server/game/Handlers/CharacterHandler.cpp @@ -308,7 +308,7 @@ void WorldSession::HandleCharEnumOpcode(WorldPackets::Character::EnumCharacters& stmt->setUInt32(0, GetAccountId()); - _queryProcessor.AddQuery(CharacterDatabase.AsyncQuery(stmt).WithPreparedCallback(std::bind(&WorldSession::HandleCharEnum, this, std::placeholders::_1))); + _queryProcessor.AddCallback(CharacterDatabase.AsyncQuery(stmt).WithPreparedCallback(std::bind(&WorldSession::HandleCharEnum, this, std::placeholders::_1))); } void WorldSession::HandleCharCreateOpcode(WorldPacket& recvData) @@ -445,7 +445,7 @@ void WorldSession::HandleCharCreateOpcode(WorldPacket& recvData) CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHECK_NAME); stmt->setString(0, createInfo->Name); - _queryProcessor.AddQuery(CharacterDatabase.AsyncQuery(stmt) + _queryProcessor.AddCallback(CharacterDatabase.AsyncQuery(stmt) .WithChainingPreparedCallback([this](QueryCallback& queryCallback, PreparedQueryResult result) { if (result) @@ -1282,7 +1282,7 @@ void WorldSession::HandleCharRenameOpcode(WorldPacket& recvData) stmt->setUInt32(1, GetAccountId()); stmt->setString(2, renameInfo->Name); - _queryProcessor.AddQuery(CharacterDatabase.AsyncQuery(stmt) + _queryProcessor.AddCallback(CharacterDatabase.AsyncQuery(stmt) .WithPreparedCallback(std::bind(&WorldSession::HandleCharRenameCallback, this, renameInfo, std::placeholders::_1))); } @@ -1527,7 +1527,7 @@ void WorldSession::HandleCharCustomize(WorldPacket& recvData) CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHAR_CUSTOMIZE_INFO); stmt->setUInt32(0, customizeInfo->Guid.GetCounter()); - _queryProcessor.AddQuery(CharacterDatabase.AsyncQuery(stmt) + _queryProcessor.AddCallback(CharacterDatabase.AsyncQuery(stmt) .WithPreparedCallback(std::bind(&WorldSession::HandleCharCustomizeCallback, this, customizeInfo, std::placeholders::_1))); } @@ -1783,7 +1783,7 @@ void WorldSession::HandleCharFactionOrRaceChange(WorldPacket& recvData) CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHAR_RACE_OR_FACTION_CHANGE_INFOS); stmt->setUInt32(0, factionChangeInfo->Guid.GetCounter()); - _queryProcessor.AddQuery(CharacterDatabase.AsyncQuery(stmt) + _queryProcessor.AddCallback(CharacterDatabase.AsyncQuery(stmt) .WithPreparedCallback(std::bind(&WorldSession::HandleCharFactionOrRaceChangeCallback, this, factionChangeInfo, std::placeholders::_1))); } diff --git a/src/server/game/Handlers/GuildHandler.cpp b/src/server/game/Handlers/GuildHandler.cpp index eedbe7a575a..965983002eb 100644 --- a/src/server/game/Handlers/GuildHandler.cpp +++ b/src/server/game/Handlers/GuildHandler.cpp @@ -886,7 +886,7 @@ void WorldSession::HandleGuildRenameRequest(WorldPacket& recvPacket) stmt->setUInt32(1, pGuild->GetId()); stmt->setString(0, newName); - _queryProcessor.AddQuery(CharacterDatabase.AsyncQuery(stmt).WithPreparedCallback(std::bind(&WorldSession::HandleGuildRenameCallback, this, newName, std::placeholders::_1))); + _queryProcessor.AddCallback(CharacterDatabase.AsyncQuery(stmt).WithPreparedCallback(std::bind(&WorldSession::HandleGuildRenameCallback, this, newName, std::placeholders::_1))); WorldPacket data(SMSG_GUILD_FLAGGED_FOR_RENAME,1); diff --git a/src/server/game/Handlers/SpellHandler.cpp b/src/server/game/Handlers/SpellHandler.cpp index a23b155bd4a..7923e4d837e 100644 --- a/src/server/game/Handlers/SpellHandler.cpp +++ b/src/server/game/Handlers/SpellHandler.cpp @@ -268,7 +268,7 @@ void WorldSession::HandleOpenItemOpcode(WorldPacket& recvPacket) CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_GIFT_BY_ITEM); stmt->setUInt32(0, item->GetGUID().GetCounter()); - _queryProcessor.AddQuery(CharacterDatabase.AsyncQuery(stmt) + _queryProcessor.AddCallback(CharacterDatabase.AsyncQuery(stmt) .WithPreparedCallback(std::bind(&WorldSession::HandleOpenWrappedItemCallback, this, item->GetPos(), item->GetGUID(), std::placeholders::_1))); } else diff --git a/src/server/game/Server/WorldSession.cpp b/src/server/game/Server/WorldSession.cpp index 21f10a2aa87..a1af493ded4 100644 --- a/src/server/game/Server/WorldSession.cpp +++ b/src/server/game/Server/WorldSession.cpp @@ -244,7 +244,7 @@ void WorldSession::SendPacket(WorldPacket const* packet, bool forced /*= false*/ { if (packet->GetConnection() != CONNECTION_TYPE_INSTANCE && IsInstanceOnlyOpcode(packet->GetOpcode())) { - TC_LOG_ERROR("network.opcode", "Prevented sending of instance only opcode %u with connection type %u to %s", packet->GetOpcode(), packet->GetConnection(), GetPlayerInfo().c_str()); + TC_LOG_ERROR("network.opcode", "Prevented sending of instance only opcode %u with connection type %u to %s", packet->GetOpcode(), uint32(packet->GetConnection()), GetPlayerInfo().c_str()); return; } @@ -253,7 +253,7 @@ void WorldSession::SendPacket(WorldPacket const* packet, bool forced /*= false*/ if (!m_Socket[conIdx]) { - TC_LOG_ERROR("network.opcode", "Prevented sending of %s to non existent socket %u to %s", GetOpcodeNameForLogging(static_cast(packet->GetOpcode())).c_str(), conIdx, GetPlayerInfo().c_str()); + TC_LOG_ERROR("network.opcode", "Prevented sending of %s to non existent socket %u to %s", GetOpcodeNameForLogging(static_cast(packet->GetOpcode())).c_str(), uint32(conIdx), GetPlayerInfo().c_str()); return; } @@ -1122,7 +1122,8 @@ void WorldSession::SetPlayer(Player* player) void WorldSession::ProcessQueryCallbacks() { - _queryProcessor.ProcessReadyQueries(); + _queryProcessor.ProcessReadyCallbacks(); + _transactionCallbacks.ProcessReadyCallbacks(); if (_realmAccountLoginCallback.valid() && _realmAccountLoginCallback.wait_for(std::chrono::seconds(0)) == std::future_status::ready) InitializeSessionCallback(static_cast(_realmAccountLoginCallback.get())); @@ -1132,6 +1133,11 @@ void WorldSession::ProcessQueryCallbacks() HandlePlayerLogin(reinterpret_cast(_charLoginCallback.get())); } +TransactionCallback& WorldSession::AddTransactionCallback(TransactionCallback&& callback) +{ + return _transactionCallbacks.AddCallback(std::move(callback)); +} + void WorldSession::InitWarden(BigNumber* k, std::string const& os) { if (os == "Win") diff --git a/src/server/game/Server/WorldSession.h b/src/server/game/Server/WorldSession.h index 284c2030370..5c29dc40c05 100644 --- a/src/server/game/Server/WorldSession.h +++ b/src/server/game/Server/WorldSession.h @@ -23,11 +23,11 @@ #define __WORLDSESSION_H #include "Common.h" +#include "AsyncCallbackProcessor.h" #include "DatabaseEnvFwd.h" #include "LockedQueue.h" #include "ObjectGuid.h" #include "Packet.h" -#include "QueryCallbackProcessor.h" #include "SharedDefines.h" #include #include @@ -1200,6 +1200,7 @@ class TC_GAME_API WorldSession public: QueryCallbackProcessor& GetQueryProcessor() { return _queryProcessor; } + TransactionCallback& AddTransactionCallback(TransactionCallback&& callback); // Compact Unit Frames (4.x) void HandleSaveCUFProfiles(WorldPacket& recvPacket); @@ -1213,6 +1214,7 @@ class TC_GAME_API WorldSession QueryResultHolderFuture _charLoginCallback; QueryCallbackProcessor _queryProcessor; + AsyncCallbackProcessor _transactionCallbacks; friend class World; protected: diff --git a/src/server/game/Server/WorldSocket.cpp b/src/server/game/Server/WorldSocket.cpp index 32b26dc3abc..7fde9e3a6b6 100644 --- a/src/server/game/Server/WorldSocket.cpp +++ b/src/server/game/Server/WorldSocket.cpp @@ -74,7 +74,7 @@ void WorldSocket::Start() LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_IP_INFO); stmt->setString(0, ip_address); - _queryProcessor.AddQuery(LoginDatabase.AsyncQuery(stmt).WithPreparedCallback(std::bind(&WorldSocket::CheckIpCallback, this, std::placeholders::_1))); + _queryProcessor.AddCallback(LoginDatabase.AsyncQuery(stmt).WithPreparedCallback(std::bind(&WorldSocket::CheckIpCallback, this, std::placeholders::_1))); } void WorldSocket::CheckIpCallback(PreparedQueryResult result) @@ -154,7 +154,7 @@ bool WorldSocket::Update() if (!BaseSocket::Update()) return false; - _queryProcessor.ProcessReadyQueries(); + _queryProcessor.ProcessReadyCallbacks(); return true; } @@ -541,7 +541,7 @@ void WorldSocket::HandleAuthSession(std::shared_ptrsetInt32(0, int32(realm.Id.Realm)); stmt->setString(1, authSession->Account); - _queryProcessor.AddQuery(LoginDatabase.AsyncQuery(stmt).WithPreparedCallback(std::bind(&WorldSocket::HandleAuthSessionCallback, this, authSession, std::placeholders::_1))); + _queryProcessor.AddCallback(LoginDatabase.AsyncQuery(stmt).WithPreparedCallback(std::bind(&WorldSocket::HandleAuthSessionCallback, this, authSession, std::placeholders::_1))); } void WorldSocket::HandleAuthSessionCallback(std::shared_ptr authSession, PreparedQueryResult result) @@ -700,7 +700,7 @@ void WorldSocket::HandleAuthSessionCallback(std::shared_ptrInitWarden(&account.Game.SessionKey, account.BattleNet.OS); - _queryProcessor.AddQuery(_worldSession->LoadPermissionsAsync().WithPreparedCallback(std::bind(&WorldSocket::LoadSessionPermissionsCallback, this, std::placeholders::_1))); + _queryProcessor.AddCallback(_worldSession->LoadPermissionsAsync().WithPreparedCallback(std::bind(&WorldSocket::LoadSessionPermissionsCallback, this, std::placeholders::_1))); AsyncRead(); } @@ -732,7 +732,7 @@ void WorldSocket::HandleAuthContinuedSession(std::shared_ptrsetUInt32(0, accountId); - _queryProcessor.AddQuery(LoginDatabase.AsyncQuery(stmt).WithPreparedCallback(std::bind(&WorldSocket::HandleAuthContinuedSessionCallback, this, authSession, std::placeholders::_1))); + _queryProcessor.AddCallback(LoginDatabase.AsyncQuery(stmt).WithPreparedCallback(std::bind(&WorldSocket::HandleAuthContinuedSessionCallback, this, authSession, std::placeholders::_1))); } void WorldSocket::HandleAuthContinuedSessionCallback(std::shared_ptr authSession, PreparedQueryResult result) diff --git a/src/server/game/Server/WorldSocket.h b/src/server/game/Server/WorldSocket.h index 00cb3d23fe4..b4f0f9d7a0a 100644 --- a/src/server/game/Server/WorldSocket.h +++ b/src/server/game/Server/WorldSocket.h @@ -18,8 +18,9 @@ #ifndef __WORLDSOCKET_H__ #define __WORLDSOCKET_H__ -#include "BigNumber.h" #include "Common.h" +#include "AsyncCallbackProcessor.h" +#include "BigNumber.h" #include "WorldPacketCrypt.h" #include "ServerPktHeader.h" #include "Socket.h" diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp index d7ee0243ce6..0ceaf229bb3 100644 --- a/src/server/game/World/World.cpp +++ b/src/server/game/World/World.cpp @@ -3179,7 +3179,7 @@ void World::UpdateRealmCharCount(uint32 accountId) { CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_COUNT); stmt->setUInt32(0, accountId); - _queryProcessor.AddQuery(CharacterDatabase.AsyncQuery(stmt).WithPreparedCallback(std::bind(&World::_UpdateRealmCharCount, this, std::placeholders::_1))); + _queryProcessor.AddCallback(CharacterDatabase.AsyncQuery(stmt).WithPreparedCallback(std::bind(&World::_UpdateRealmCharCount, this, std::placeholders::_1))); } void World::_UpdateRealmCharCount(PreparedQueryResult resultCharCount) @@ -3614,7 +3614,7 @@ uint64 World::getWorldState(uint32 index) const void World::ProcessQueryCallbacks() { - _queryProcessor.ProcessReadyQueries(); + _queryProcessor.ProcessReadyCallbacks(); } void World::ReloadRBAC() diff --git a/src/server/game/World/World.h b/src/server/game/World/World.h index ef12bcdbb44..454b9c96451 100644 --- a/src/server/game/World/World.h +++ b/src/server/game/World/World.h @@ -23,10 +23,10 @@ #define __WORLD_H #include "Common.h" +#include "AsyncCallbackProcessor.h" #include "DatabaseEnvFwd.h" #include "LockedQueue.h" #include "ObjectGuid.h" -#include "QueryCallbackProcessor.h" #include "SharedDefines.h" #include "Timer.h"