Core/DBLayer: Implement async transaction completion callbacks
This commit is contained in:
1 parent
882c275e65
commit
ca881f7e3f
22 files changed
+246
-141
No files matched your search
@@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef AsyncCallbackProcessor_h__
|
||||
#define AsyncCallbackProcessor_h__
|
||||
|
||||
#include "Define.h"
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
|
||||
//template <class T>
|
||||
//concept AsyncCallback = requires(T t) { { t.InvokeIfReady() } -> std::convertible_to<bool> };
|
||||
|
||||
template<typename T> // requires AsyncCallback<T>
|
||||
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<T> 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<T> _callbacks;
|
||||
};
|
||||
|
||||
#endif // AsyncCallbackProcessor_h__
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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 <memory>
|
||||
#include <boost/asio/ip/tcp.hpp>
|
||||
|
||||
@@ -24,9 +24,9 @@
|
||||
class Field;
|
||||
|
||||
class ResultSet;
|
||||
typedef std::shared_ptr<ResultSet> QueryResult;
|
||||
typedef std::future<QueryResult> QueryResultFuture;
|
||||
typedef std::promise<QueryResult> QueryResultPromise;
|
||||
using QueryResult = std::shared_ptr<ResultSet>;
|
||||
using QueryResultFuture = std::future<QueryResult>;
|
||||
using QueryResultPromise = std::promise<QueryResult>;
|
||||
|
||||
class CharacterDatabaseConnection;
|
||||
class HotfixDatabaseConnection;
|
||||
@@ -44,17 +44,27 @@ using LoginDatabasePreparedStatement = PreparedStatement<LoginDatabaseConnection
|
||||
using WorldDatabasePreparedStatement = PreparedStatement<WorldDatabaseConnection>;
|
||||
|
||||
class PreparedResultSet;
|
||||
typedef std::shared_ptr<PreparedResultSet> PreparedQueryResult;
|
||||
typedef std::future<PreparedQueryResult> PreparedQueryResultFuture;
|
||||
typedef std::promise<PreparedQueryResult> PreparedQueryResultPromise;
|
||||
using PreparedQueryResult = std::shared_ptr<PreparedResultSet>;
|
||||
using PreparedQueryResultFuture = std::future<PreparedQueryResult>;
|
||||
using PreparedQueryResultPromise = std::promise<PreparedQueryResult>;
|
||||
|
||||
class QueryCallback;
|
||||
|
||||
template<typename T>
|
||||
class AsyncCallbackProcessor;
|
||||
|
||||
using QueryCallbackProcessor = AsyncCallbackProcessor<QueryCallback>;
|
||||
|
||||
class TransactionBase;
|
||||
|
||||
using TransactionFuture = std::future<bool>;
|
||||
using TransactionPromise = std::promise<bool>;
|
||||
|
||||
template<typename T>
|
||||
class Transaction;
|
||||
|
||||
class TransactionCallback;
|
||||
|
||||
template<typename T>
|
||||
using SQLTransaction = std::shared_ptr<Transaction<T>>;
|
||||
|
||||
@@ -64,8 +74,8 @@ using LoginDatabaseTransaction = SQLTransaction<LoginDatabaseConnection>;
|
||||
using WorldDatabaseTransaction = SQLTransaction<WorldDatabaseConnection>;
|
||||
|
||||
class SQLQueryHolderBase;
|
||||
typedef std::future<SQLQueryHolderBase*> QueryResultHolderFuture;
|
||||
typedef std::promise<SQLQueryHolderBase*> QueryResultHolderPromise;
|
||||
using QueryResultHolderFuture = std::future<SQLQueryHolderBase*>;
|
||||
using QueryResultHolderPromise = std::promise<SQLQueryHolderBase*>;
|
||||
|
||||
template<typename T>
|
||||
class SQLQueryHolder;
|
||||
|
||||
@@ -261,6 +261,32 @@ void DatabaseWorkerPool<T>::CommitTransaction(SQLTransaction<T> transaction)
|
||||
Enqueue(new TransactionTask(transaction));
|
||||
}
|
||||
|
||||
template <class T>
|
||||
TransactionCallback DatabaseWorkerPool<T>::AsyncCommitTransaction(SQLTransaction<T> 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 <class T>
|
||||
void DatabaseWorkerPool<T>::DirectCommitTransaction(SQLTransaction<T>& transaction)
|
||||
{
|
||||
|
||||
@@ -173,6 +173,10 @@ class DatabaseWorkerPool
|
||||
//! were appended to the transaction will be respected during execution.
|
||||
void CommitTransaction(SQLTransaction<T> 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<T> 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<T>& transaction);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "QueryCallbackProcessor.h"
|
||||
#include "QueryCallback.h"
|
||||
#include <algorithm>
|
||||
|
||||
QueryCallbackProcessor::QueryCallbackProcessor()
|
||||
{
|
||||
}
|
||||
|
||||
QueryCallbackProcessor::~QueryCallbackProcessor()
|
||||
{
|
||||
}
|
||||
|
||||
void QueryCallbackProcessor::AddQuery(QueryCallback&& query)
|
||||
{
|
||||
_callbacks.emplace_back(std::move(query));
|
||||
}
|
||||
|
||||
void QueryCallbackProcessor::ProcessReadyQueries()
|
||||
{
|
||||
if (_callbacks.empty())
|
||||
return;
|
||||
|
||||
std::vector<QueryCallback> 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()));
|
||||
}
|
||||
@@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef QueryCallbackProcessor_h__
|
||||
#define QueryCallbackProcessor_h__
|
||||
|
||||
#include "Define.h"
|
||||
#include <vector>
|
||||
|
||||
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<QueryCallback> _callbacks;
|
||||
};
|
||||
|
||||
#endif // QueryCallbackProcessor_h__
|
||||
@@ -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<std::mutex> 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;
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include "DatabaseEnvFwd.h"
|
||||
#include "SQLOperation.h"
|
||||
#include "StringFormat.h"
|
||||
#include <functional>
|
||||
#include <mutex>
|
||||
#include <vector>
|
||||
|
||||
@@ -73,6 +74,7 @@ class TC_DATABASE_API TransactionTask : public SQLOperation
|
||||
{
|
||||
template <class T> friend class DatabaseWorkerPool;
|
||||
friend class DatabaseWorker;
|
||||
friend class TransactionCallback;
|
||||
|
||||
public:
|
||||
TransactionTask(std::shared_ptr<TransactionBase> 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<TransactionBase> m_trans;
|
||||
static std::mutex _deadlockLock;
|
||||
};
|
||||
|
||||
class TC_DATABASE_API TransactionWithResultTask : public TransactionTask
|
||||
{
|
||||
public:
|
||||
TransactionWithResultTask(std::shared_ptr<TransactionBase> 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<void(bool)> callback) &
|
||||
{
|
||||
m_callback = std::move(callback);
|
||||
}
|
||||
|
||||
bool InvokeIfReady();
|
||||
|
||||
TransactionFuture m_future;
|
||||
std::function<void(bool)> m_callback;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -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
|
||||
|
||||
@@ -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)));
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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<OpcodeServer>(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<OpcodeServer>(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<LoginDatabaseQueryHolder*>(_realmAccountLoginCallback.get()));
|
||||
@@ -1132,6 +1133,11 @@ void WorldSession::ProcessQueryCallbacks()
|
||||
HandlePlayerLogin(reinterpret_cast<LoginQueryHolder*>(_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")
|
||||
|
||||
@@ -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 <map>
|
||||
#include <unordered_map>
|
||||
@@ -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<TransactionCallback> _transactionCallbacks;
|
||||
|
||||
friend class World;
|
||||
protected:
|
||||
|
||||
@@ -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_ptr<WorldPackets::Auth::AuthSess
|
||||
stmt->setInt32(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<WorldPackets::Auth::AuthSession> authSession, PreparedQueryResult result)
|
||||
@@ -700,7 +700,7 @@ void WorldSocket::HandleAuthSessionCallback(std::shared_ptr<WorldPackets::Auth::
|
||||
if (wardenActive)
|
||||
_worldSession->InitWarden(&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_ptr<WorldPackets::Auth:
|
||||
LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_ACCOUNT_INFO_CONTINUED_SESSION);
|
||||
stmt->setUInt32(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<WorldPackets::Auth::AuthContinuedSession> authSession, PreparedQueryResult result)
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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"
|
||||
|
||||
|
||||
Reference in new issue
Block a user