From d450f6db3dbb1fe267c3c6c68ea8a01088dbe6d0 Mon Sep 17 00:00:00 2001 From: hondacrx Date: Sun, 26 Apr 2020 00:53:43 -0400 Subject: [PATCH] Core/DBLayer: Implement async transaction completion callbacks Port From (https://github.com/TrinityCore/TrinityCore/commit/0f0ca3a9194d76afa0227943e86469ad8368c5e2) --- Source/BNetServer/Networking/Session.cs | 6 +- ...Processor.cs => AsyncCallbackProcessor.cs} | 18 ++-- Source/Framework/Database/MySqlBase.cs | 15 +++- Source/Framework/Database/QueryCallback.cs | 17 ++-- Source/Framework/Database/SQLTransaction.cs | 90 +++++++++++++++++++ Source/Game/Entities/Object/ObjectGuid.cs | 1 + Source/Game/Entities/Player/Player.DB.cs | 89 +++++++++--------- Source/Game/Entities/Player/Player.Talents.cs | 2 +- Source/Game/Handlers/CharacterHandler.cs | 60 +++++++------ Source/Game/Handlers/NPCHandler.cs | 2 +- Source/Game/Handlers/SpellHandler.cs | 2 +- Source/Game/Network/WorldSocket.cs | 12 +-- Source/Game/Server/WorldManager.cs | 6 +- Source/Game/Server/WorldSession.cs | 13 ++- 14 files changed, 224 insertions(+), 109 deletions(-) rename Source/Framework/Database/{QueryCallbackProcessor.cs => AsyncCallbackProcessor.cs} (76%) diff --git a/Source/BNetServer/Networking/Session.cs b/Source/BNetServer/Networking/Session.cs index bd7999c9d..450e7e3ba 100644 --- a/Source/BNetServer/Networking/Session.cs +++ b/Source/BNetServer/Networking/Session.cs @@ -55,7 +55,7 @@ namespace BNetServer.Networking stmt.AddValue(0, ip_address); stmt.AddValue(1, BitConverter.ToUInt32(GetRemoteIpAddress().GetAddressBytes(), 0)); - _queryProcessor.AddQuery(DB.Login.AsyncQuery(stmt).WithCallback(CheckIpCallback)); + _queryProcessor.AddCallback(DB.Login.AsyncQuery(stmt).WithCallback(CheckIpCallback)); } void CheckIpCallback(SQLResult result) @@ -89,7 +89,7 @@ namespace BNetServer.Networking if (!base.Update()) return false; - _queryProcessor.ProcessReadyQueries(); + _queryProcessor.ProcessReadyCallbacks(); return true; } @@ -631,7 +631,7 @@ namespace BNetServer.Networking bool _authed; - QueryCallbackProcessor _queryProcessor = new QueryCallbackProcessor(); + AsyncCallbackProcessor _queryProcessor = new AsyncCallbackProcessor(); Dictionary> _responseCallbacks = new Dictionary>(); uint _requestToken; diff --git a/Source/Framework/Database/QueryCallbackProcessor.cs b/Source/Framework/Database/AsyncCallbackProcessor.cs similarity index 76% rename from Source/Framework/Database/QueryCallbackProcessor.cs rename to Source/Framework/Database/AsyncCallbackProcessor.cs index d126fdeb1..2f90c0ea2 100644 --- a/Source/Framework/Database/QueryCallbackProcessor.cs +++ b/Source/Framework/Database/AsyncCallbackProcessor.cs @@ -19,21 +19,27 @@ using System.Collections.Generic; namespace Framework.Database { - public class QueryCallbackProcessor + public interface ISqlCallback { - public void AddQuery(QueryCallback query) + bool InvokeIfReady(); + } + + public class AsyncCallbackProcessor where T : ISqlCallback + { + List _callbacks = new List(); + + public T AddCallback(T query) { _callbacks.Add(query); + return query; } - public void ProcessReadyQueries() + public void ProcessReadyCallbacks() { if (_callbacks.Empty()) return; - _callbacks.RemoveAll(callback => callback.InvokeIfReady() == QueryCallbackStatus.Completed); + _callbacks.RemoveAll(callback => callback.InvokeIfReady()); } - - List _callbacks = new List(); } } diff --git a/Source/Framework/Database/MySqlBase.cs b/Source/Framework/Database/MySqlBase.cs index f4e60aa09..a8f48dadb 100644 --- a/Source/Framework/Database/MySqlBase.cs +++ b/Source/Framework/Database/MySqlBase.cs @@ -253,7 +253,15 @@ namespace Framework.Database _queue.Push(new TransactionTask(transaction)); } - public bool DirectCommitTransaction(SQLTransaction transaction) + public TransactionCallback AsyncCommitTransaction(SQLTransaction transaction) + { + TransactionWithResultTask task = new TransactionWithResultTask(transaction); + Task result = task.GetFuture(); + _queue.Push(task); + return new TransactionCallback(result); + } + + public MySqlErrorCode DirectCommitTransaction(SQLTransaction transaction) { using (var Connection = _connectionInfo.GetConnection()) { @@ -277,13 +285,12 @@ namespace Framework.Database trans.Commit(); scope.Complete(); } - return true; + return MySqlErrorCode.None; } catch (MySqlException ex) //error occurred { - HandleMySQLException(ex, query); trans.Rollback(); - return false; + return HandleMySQLException(ex, query); } } } diff --git a/Source/Framework/Database/QueryCallback.cs b/Source/Framework/Database/QueryCallback.cs index 7b414bf68..440a40a1d 100644 --- a/Source/Framework/Database/QueryCallback.cs +++ b/Source/Framework/Database/QueryCallback.cs @@ -21,7 +21,7 @@ using System.Threading.Tasks; namespace Framework.Database { - public class QueryCallback + public class QueryCallback : ISqlCallback { public QueryCallback(Task result) { @@ -49,7 +49,7 @@ namespace Framework.Database _result = next._result; } - public QueryCallbackStatus InvokeIfReady() + public bool InvokeIfReady() { QueryCallbackData callback = _callbacks.Peek(); @@ -68,17 +68,17 @@ namespace Framework.Database if (_callbacks.Count == 0) { Cypher.Assert(!hasNext); - return QueryCallbackStatus.Completed; + return true; } // abort chain if (!hasNext) - return QueryCallbackStatus.Completed; + return true; callback = _callbacks.Peek(); } else - return QueryCallbackStatus.NotReady; + return false; } } @@ -100,11 +100,4 @@ namespace Framework.Database public Action _result; } - - public enum QueryCallbackStatus - { - NotReady, - NextStep, - Completed - } } diff --git a/Source/Framework/Database/SQLTransaction.cs b/Source/Framework/Database/SQLTransaction.cs index 88463c0ec..003b84a46 100644 --- a/Source/Framework/Database/SQLTransaction.cs +++ b/Source/Framework/Database/SQLTransaction.cs @@ -17,6 +17,8 @@ using MySql.Data.MySqlClient; using System.Collections.Generic; +using System; +using System.Threading.Tasks; namespace Framework.Database { @@ -52,10 +54,98 @@ namespace Framework.Database } public bool Execute(MySqlBase mySqlBase) + { + MySqlErrorCode errorCode = TryExecute(mySqlBase); + if (errorCode == MySqlErrorCode.None) + return true; + + if (errorCode == MySqlErrorCode.LockDeadlock) + { + // Make sure only 1 async thread retries a transaction so they don't keep dead-locking each other + lock (_deadlockLock) + { + byte loopBreaker = 5; // Handle MySQL Errno 1213 without extending deadlock to the core itself + for (byte i = 0; i < loopBreaker; ++i) + if (TryExecute(mySqlBase) == MySqlErrorCode.None) + return true; + } + } + + return false; + } + + public MySqlErrorCode TryExecute(MySqlBase mySqlBase) { return mySqlBase.DirectCommitTransaction(m_trans); } SQLTransaction m_trans; + public static object _deadlockLock = new object(); + } + + class TransactionWithResultTask : TransactionTask + { + public TransactionWithResultTask(SQLTransaction trans) : base(trans) { } + + public new bool Execute(MySqlBase mySqlBase) + { + MySqlErrorCode errorCode = TryExecute(mySqlBase); + if (errorCode == MySqlErrorCode.None) + { + m_result.SetResult(true); + return true; + } + + if (errorCode == MySqlErrorCode.LockDeadlock) + { + // Make sure only 1 async thread retries a transaction so they don't keep dead-locking each other + lock (_deadlockLock) + { + byte loopBreaker = 5; // Handle MySQL Errno 1213 without extending deadlock to the core itself + for (byte i = 0; i < loopBreaker; ++i) + { + if (TryExecute(mySqlBase) == MySqlErrorCode.None) + { + m_result.SetResult(true); + return true; + } + } + } + } + + m_result.SetResult(false); + return false; + } + + public Task GetFuture() { return m_result.Task; } + + TaskCompletionSource m_result = new TaskCompletionSource(); + } + + public class TransactionCallback : ISqlCallback + { + public TransactionCallback(Task future) + { + m_future = future; + } + + public void AfterComplete(Action callback) + { + m_callback = callback; + } + + public bool InvokeIfReady() + { + if (m_future != null && m_future.Wait(0)) + { + m_callback(m_future.Result); + return true; + } + + return false; + } + + Task m_future; + Action m_callback; } } diff --git a/Source/Game/Entities/Object/ObjectGuid.cs b/Source/Game/Entities/Object/ObjectGuid.cs index 66ff3f259..7fc76b80e 100644 --- a/Source/Game/Entities/Object/ObjectGuid.cs +++ b/Source/Game/Entities/Object/ObjectGuid.cs @@ -73,6 +73,7 @@ namespace Game.Entities { return MapSpecificCreate(type, (byte)subType, (ushort)mapId, 0, entry, counter); } + static ObjectGuid GlobalCreate(HighGuid type, ulong counter) { return new ObjectGuid((ulong)type << 58, counter); diff --git a/Source/Game/Entities/Player/Player.DB.cs b/Source/Game/Entities/Player/Player.DB.cs index 949097384..53c43f6f2 100644 --- a/Source/Game/Entities/Player/Player.DB.cs +++ b/Source/Game/Entities/Player/Player.DB.cs @@ -3107,6 +3107,17 @@ namespace Game.Entities } public void SaveToDB(bool create = false) + { + SQLTransaction loginTransaction = new SQLTransaction(); + SQLTransaction characterTransaction = new SQLTransaction(); + + SaveToDB(loginTransaction, characterTransaction, create); + + DB.Characters.CommitTransaction(characterTransaction); + DB.Login.CommitTransaction(loginTransaction); + } + + public void SaveToDB(SQLTransaction loginTransaction, SQLTransaction characterTransaction, bool create = false) { // delay auto save at any saves (manual, in code, or autosave) m_nextSave = WorldConfig.GetUIntValue(WorldCfg.IntervalSave); @@ -3126,13 +3137,12 @@ namespace Game.Entities if (!create) Global.ScriptMgr.OnPlayerSave(this); - SQLTransaction trans = new SQLTransaction(); PreparedStatement stmt; byte index = 0; stmt = DB.Characters.GetPreparedStatement(CharStatements.DEL_CHAR_FISHINGSTEPS); stmt.AddValue(0, GetGUID().GetCounter()); - trans.Append(stmt); + characterTransaction.Append(stmt); float finiteAlways(float f) { return !float.IsInfinity(f) ? f : 0.0f; }; @@ -3428,7 +3438,7 @@ namespace Game.Entities stmt.AddValue(index, GetGUID().GetCounter()); } - trans.Append(stmt); + characterTransaction.Append(stmt); if (m_fishingSteps != 0) { @@ -3436,58 +3446,55 @@ namespace Game.Entities index = 0; stmt.AddValue(index++, GetGUID().GetCounter()); stmt.AddValue(index++, m_fishingSteps); - trans.Append(stmt); + characterTransaction.Append(stmt); } if (m_mailsUpdated) //save mails only when needed - _SaveMail(trans); + _SaveMail(characterTransaction); - _SaveBGData(trans); - _SaveInventory(trans); - _SaveVoidStorage(trans); - _SaveQuestStatus(trans); - _SaveDailyQuestStatus(trans); - _SaveWeeklyQuestStatus(trans); - _SaveSeasonalQuestStatus(trans); - _SaveMonthlyQuestStatus(trans); - _SaveGlyphs(trans); - _SaveTalents(trans); - _SaveSpells(trans); - GetSpellHistory().SaveToDB(trans); - _SaveActions(trans); - _SaveAuras(trans); - _SaveSkills(trans); - m_achievementSys.SaveToDB(trans); - reputationMgr.SaveToDB(trans); - m_questObjectiveCriteriaMgr.SaveToDB(trans); - _SaveEquipmentSets(trans); - GetSession().SaveTutorialsData(trans); // changed only while character in game - _SaveInstanceTimeRestrictions(trans); - _SaveCurrency(trans); - _SaveCUFProfiles(trans); + _SaveBGData(characterTransaction); + _SaveInventory(characterTransaction); + _SaveVoidStorage(characterTransaction); + _SaveQuestStatus(characterTransaction); + _SaveDailyQuestStatus(characterTransaction); + _SaveWeeklyQuestStatus(characterTransaction); + _SaveSeasonalQuestStatus(characterTransaction); + _SaveMonthlyQuestStatus(characterTransaction); + _SaveGlyphs(characterTransaction); + _SaveTalents(characterTransaction); + _SaveSpells(characterTransaction); + GetSpellHistory().SaveToDB(characterTransaction); + _SaveActions(characterTransaction); + _SaveAuras(characterTransaction); + _SaveSkills(characterTransaction); + m_achievementSys.SaveToDB(characterTransaction); + reputationMgr.SaveToDB(characterTransaction); + m_questObjectiveCriteriaMgr.SaveToDB(characterTransaction); + _SaveEquipmentSets(characterTransaction); + GetSession().SaveTutorialsData(characterTransaction); // changed only while character in game + _SaveInstanceTimeRestrictions(characterTransaction); + _SaveCurrency(characterTransaction); + _SaveCUFProfiles(characterTransaction); if (_garrison != null) - _garrison.SaveToDB(trans); + _garrison.SaveToDB(characterTransaction); // check if stats should only be saved on logout // save stats can be out of transaction if (GetSession().IsLogingOut() || !WorldConfig.GetBoolValue(WorldCfg.StatsSaveOnlyOnLogout)) - _SaveStats(trans); - - DB.Characters.CommitTransaction(trans); + _SaveStats(characterTransaction); // TODO: Move this out - trans = new SQLTransaction(); - GetSession().GetCollectionMgr().SaveAccountToys(trans); - GetSession().GetBattlePetMgr().SaveToDB(trans); - GetSession().GetCollectionMgr().SaveAccountHeirlooms(trans); - GetSession().GetCollectionMgr().SaveAccountMounts(trans); - GetSession().GetCollectionMgr().SaveAccountItemAppearances(trans); + GetSession().GetCollectionMgr().SaveAccountToys(loginTransaction); + GetSession().GetBattlePetMgr().SaveToDB(loginTransaction); + GetSession().GetCollectionMgr().SaveAccountHeirlooms(loginTransaction); + GetSession().GetCollectionMgr().SaveAccountMounts(loginTransaction); + GetSession().GetCollectionMgr().SaveAccountItemAppearances(loginTransaction); stmt = DB.Login.GetPreparedStatement(LoginStatements.DEL_BNET_LAST_PLAYER_CHARACTERS); stmt.AddValue(0, GetSession().GetAccountId()); stmt.AddValue(1, Global.WorldMgr.GetRealmId().Region); stmt.AddValue(2, Global.WorldMgr.GetRealmId().Site); - trans.Append(stmt); + loginTransaction.Append(stmt); stmt = DB.Login.GetPreparedStatement(LoginStatements.INS_BNET_LAST_PLAYER_CHARACTERS); stmt.AddValue(0, GetSession().GetAccountId()); @@ -3497,9 +3504,7 @@ namespace Game.Entities stmt.AddValue(4, GetName()); stmt.AddValue(5, GetGUID().GetCounter()); stmt.AddValue(6, Time.UnixTime); - trans.Append(stmt); - - DB.Login.CommitTransaction(trans); + loginTransaction.Append(stmt); // save pet (hunter pet level and experience and all type pets health/mana). Pet pet = GetPet(); diff --git a/Source/Game/Entities/Player/Player.Talents.cs b/Source/Game/Entities/Player/Player.Talents.cs index 3f5d13218..bafe4b12f 100644 --- a/Source/Game/Entities/Player/Player.Talents.cs +++ b/Source/Game/Entities/Player/Player.Talents.cs @@ -383,7 +383,7 @@ namespace Game.Entities stmt.AddValue(1, GetActiveTalentGroup()); WorldSession mySess = GetSession(); - mySess.GetQueryProcessor().AddQuery(DB.Characters.AsyncQuery(stmt).WithCallback(result => + mySess.GetQueryProcessor().AddCallback(DB.Characters.AsyncQuery(stmt).WithCallback(result => { // in case player logs out before db response (player would be deleted in that case) Player thisPlayer = mySess.GetPlayer(); diff --git a/Source/Game/Handlers/CharacterHandler.cs b/Source/Game/Handlers/CharacterHandler.cs index 0c320fafa..6884d1371 100644 --- a/Source/Game/Handlers/CharacterHandler.cs +++ b/Source/Game/Handlers/CharacterHandler.cs @@ -49,7 +49,7 @@ namespace Game stmt.AddValue(0, PetSaveMode.AsCurrent); stmt.AddValue(1, GetAccountId()); - _queryProcessor.AddQuery(DB.Characters.AsyncQuery(stmt).WithCallback(HandleCharEnumCallback)); + _queryProcessor.AddCallback(DB.Characters.AsyncQuery(stmt).WithCallback(HandleCharEnumCallback)); } void HandleCharEnumCallback(SQLResult result) @@ -144,7 +144,7 @@ namespace Game stmt.AddValue(0, (uint)PetSaveMode.AsCurrent); stmt.AddValue(1, GetAccountId()); - _queryProcessor.AddQuery(DB.Characters.AsyncQuery(stmt).WithCallback(HandleCharUndeleteEnumCallback)); + _queryProcessor.AddCallback(DB.Characters.AsyncQuery(stmt).WithCallback(HandleCharUndeleteEnumCallback)); } void HandleCharUndeleteEnumCallback(SQLResult result) @@ -307,7 +307,7 @@ namespace Game PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_CHECK_NAME); stmt.AddValue(0, charCreate.CreateInfo.Name); - _queryProcessor.AddQuery(DB.Characters.AsyncQuery(stmt).WithChainingCallback((queryCallback, result) => + _queryProcessor.AddCallback(DB.Characters.AsyncQuery(stmt).WithChainingCallback((queryCallback, result) => { if (!result.IsEmpty()) { @@ -334,6 +334,7 @@ namespace Game stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_SUM_CHARS); stmt.AddValue(0, GetAccountId()); queryCallback.SetNextQuery(DB.Characters.AsyncQuery(stmt)); + }).WithChainingCallback((queryCallback, result) => { if (!result.IsEmpty()) @@ -346,17 +347,16 @@ namespace Game return; } } - + + int demonHunterReqLevel = WorldConfig.GetIntValue(WorldCfg.CharacterCreatingMinLevelForDemonHunter); + bool hasDemonHunterReqLevel = demonHunterReqLevel == 0; bool allowTwoSideAccounts = !Global.WorldMgr.IsPvPRealm() || HasPermission(RBACPermissions.TwoSideCharacterCreation); int skipCinematics = WorldConfig.GetIntValue(WorldCfg.SkipCinematics); + bool checkDemonHunterReqs = createInfo.ClassId == Class.DemonHunter && !HasPermission(RBACPermissions.SkipCheckCharacterCreationDemonHunter); void finalizeCharacterCreation(SQLResult result1) { bool haveSameRace = false; - int demonHunterReqLevel = WorldConfig.GetIntValue(WorldCfg.CharacterCreatingMinLevelForDemonHunter); - bool hasDemonHunterReqLevel = (demonHunterReqLevel == 0); - bool checkDemonHunterReqs = createInfo.ClassId == Class.DemonHunter && !HasPermission(RBACPermissions.SkipCheckCharacterCreationDemonHunter); - if (result1 != null && !result1.IsEmpty()) { Team team = Player.TeamForRace(createInfo.RaceId); @@ -461,33 +461,39 @@ namespace Game newChar.atLoginFlags = AtLoginFlags.FirstLogin; // First login - // Player created, save it now - newChar.SaveToDB(true); - createInfo.CharCount += 1; + SQLTransaction characterTransaction = new SQLTransaction(); + SQLTransaction loginTransaction = new SQLTransaction(); - SQLTransaction trans = new SQLTransaction(); + // Player created, save it now + newChar.SaveToDB(loginTransaction, characterTransaction, true); + createInfo.CharCount += 1; stmt = DB.Login.GetPreparedStatement(LoginStatements.DEL_REALM_CHARACTERS_BY_REALM); stmt.AddValue(0, GetAccountId()); stmt.AddValue(1, Global.WorldMgr.GetRealm().Id.Realm); - trans.Append(stmt); + loginTransaction.Append(stmt); stmt = DB.Login.GetPreparedStatement(LoginStatements.INS_REALM_CHARACTERS); stmt.AddValue(0, createInfo.CharCount); stmt.AddValue(1, GetAccountId()); stmt.AddValue(2, Global.WorldMgr.GetRealm().Id.Realm); - trans.Append(stmt); + loginTransaction.Append(stmt); - DB.Login.CommitTransaction(trans); + DB.Login.CommitTransaction(loginTransaction); - // Success - SendCharCreate(ResponseCodes.CharCreateSuccess, newChar.GetGUID()); + AddTransactionCallback(DB.Characters.AsyncCommitTransaction(characterTransaction)).AfterComplete(success => + { + if (success) + { + Log.outInfo(LogFilter.Player, "Account: {0} (IP: {1}) Create Character: {2} {3}", GetAccountId(), GetRemoteAddress(), createInfo.Name, newChar.GetGUID().ToString()); + Global.ScriptMgr.OnPlayerCreate(newChar); + Global.CharacterCacheStorage.AddCharacterCacheEntry(newChar.GetGUID(), GetAccountId(), newChar.GetName(), newChar.m_playerData.NativeSex, (byte)newChar.GetRace(), (byte)newChar.GetClass(), (byte)newChar.GetLevel(), false); - Log.outInfo(LogFilter.Player, "Account: {0} (IP: {1}) Create Character: {2} {3}", GetAccountId(), GetRemoteAddress(), createInfo.Name, newChar.GetGUID().ToString()); - Global.ScriptMgr.OnPlayerCreate(newChar); - Global.CharacterCacheStorage.AddCharacterCacheEntry(newChar.GetGUID(), GetAccountId(), newChar.GetName(), newChar.m_playerData.NativeSex, (byte)newChar.GetRace(), (byte)newChar.GetClass(), (byte)newChar.GetLevel(), false); - - newChar.CleanupsBeforeDelete(); + SendCharCreate(ResponseCodes.CharCreateSuccess, newChar.GetGUID()); + } + else + SendCharCreate(ResponseCodes.CharCreateError); + }); } if (!allowTwoSideAccounts || skipCinematics == 1 || createInfo.ClassId == Class.DemonHunter) @@ -1021,7 +1027,7 @@ namespace Game stmt.AddValue(0, request.RenameInfo.Guid.GetCounter()); stmt.AddValue(1, request.RenameInfo.NewName); - _queryProcessor.AddQuery(DB.Characters.AsyncQuery(stmt).WithCallback(HandleCharRenameCallBack, request.RenameInfo)); + _queryProcessor.AddCallback(DB.Characters.AsyncQuery(stmt).WithCallback(HandleCharRenameCallBack, request.RenameInfo)); } void HandleCharRenameCallBack(CharacterRenameInfo renameInfo, SQLResult result) @@ -1211,7 +1217,7 @@ namespace Game PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_CHAR_CUSTOMIZE_INFO); stmt.AddValue(0, packet.CustomizeInfo.CharGUID.GetCounter()); - _queryProcessor.AddQuery(DB.Characters.AsyncQuery(stmt).WithCallback(HandleCharCustomizeCallback, packet.CustomizeInfo)); + _queryProcessor.AddCallback(DB.Characters.AsyncQuery(stmt).WithCallback(HandleCharCustomizeCallback, packet.CustomizeInfo)); } void HandleCharCustomizeCallback(CharCustomizeInfo customizeInfo, SQLResult result) @@ -1492,7 +1498,7 @@ namespace Game PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_CHAR_RACE_OR_FACTION_CHANGE_INFOS); stmt.AddValue(0, packet.RaceOrFactionChangeInfo.Guid.GetCounter()); - _queryProcessor.AddQuery(DB.Characters.AsyncQuery(stmt).WithCallback(HandleCharRaceOrFactionChangeCallback, packet.RaceOrFactionChangeInfo)); + _queryProcessor.AddCallback(DB.Characters.AsyncQuery(stmt).WithCallback(HandleCharRaceOrFactionChangeCallback, packet.RaceOrFactionChangeInfo)); } void HandleCharRaceOrFactionChangeCallback(CharRaceOrFactionChangeInfo factionChangeInfo, SQLResult result) @@ -2045,7 +2051,7 @@ namespace Game PreparedStatement stmt = DB.Login.GetPreparedStatement(LoginStatements.SEL_LAST_CHAR_UNDELETE); stmt.AddValue(0, GetBattlenetAccountId()); - _queryProcessor.AddQuery(DB.Login.AsyncQuery(stmt).WithCallback(HandleUndeleteCooldownStatusCallback)); + _queryProcessor.AddCallback(DB.Login.AsyncQuery(stmt).WithCallback(HandleUndeleteCooldownStatusCallback)); } void HandleUndeleteCooldownStatusCallback(SQLResult result) @@ -2076,7 +2082,7 @@ namespace Game stmt.AddValue(0, GetBattlenetAccountId()); CharacterUndeleteInfo undeleteInfo = undeleteCharacter.UndeleteInfo; - _queryProcessor.AddQuery(DB.Login.AsyncQuery(stmt).WithChainingCallback((queryCallback, result) => + _queryProcessor.AddCallback(DB.Login.AsyncQuery(stmt).WithChainingCallback((queryCallback, result) => { if (!result.IsEmpty()) { diff --git a/Source/Game/Handlers/NPCHandler.cs b/Source/Game/Handlers/NPCHandler.cs index 79e4bfefe..ca75f1459 100644 --- a/Source/Game/Handlers/NPCHandler.cs +++ b/Source/Game/Handlers/NPCHandler.cs @@ -351,7 +351,7 @@ namespace Game stmt.AddValue(1, PetSaveMode.FirstStableSlot); stmt.AddValue(2, PetSaveMode.LastStableSlot); - _queryProcessor.AddQuery(DB.Characters.AsyncQuery(stmt).WithCallback(SendStablePetCallback, guid)); + _queryProcessor.AddCallback(DB.Characters.AsyncQuery(stmt).WithCallback(SendStablePetCallback, guid)); } void SendStablePetCallback(ObjectGuid guid, SQLResult result) diff --git a/Source/Game/Handlers/SpellHandler.cs b/Source/Game/Handlers/SpellHandler.cs index f6d4592ac..9b06097b1 100644 --- a/Source/Game/Handlers/SpellHandler.cs +++ b/Source/Game/Handlers/SpellHandler.cs @@ -188,7 +188,7 @@ namespace Game { PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_CHARACTER_GIFT_BY_ITEM); stmt.AddValue(0, item.GetGUID().GetCounter()); - _queryProcessor.AddQuery(DB.Characters.AsyncQuery(stmt) + _queryProcessor.AddCallback(DB.Characters.AsyncQuery(stmt) .WithCallback(result => HandleOpenWrappedItemCallback(item.GetPos(), item.GetGUID(), result))); } else diff --git a/Source/Game/Network/WorldSocket.cs b/Source/Game/Network/WorldSocket.cs index 8da3e07a1..5fcc03b0a 100644 --- a/Source/Game/Network/WorldSocket.cs +++ b/Source/Game/Network/WorldSocket.cs @@ -65,7 +65,7 @@ namespace Game.Network stmt.AddValue(0, ip_address); stmt.AddValue(1, BitConverter.ToUInt32(GetRemoteIpAddress().GetAddressBytes(), 0)); - _queryProcessor.AddQuery(DB.Login.AsyncQuery(stmt).WithCallback(CheckIpCallback)); + _queryProcessor.AddCallback(DB.Login.AsyncQuery(stmt).WithCallback(CheckIpCallback)); } void CheckIpCallback(SQLResult result) @@ -356,7 +356,7 @@ namespace Game.Network if (!base.Update()) return false; - _queryProcessor.ProcessReadyQueries(); + _queryProcessor.ProcessReadyCallbacks(); return true; } @@ -378,7 +378,7 @@ namespace Game.Network stmt.AddValue(0, Global.WorldMgr.GetRealm().Id.Realm); stmt.AddValue(1, authSession.RealmJoinTicket); - _queryProcessor.AddQuery(DB.Login.AsyncQuery(stmt).WithCallback(HandleAuthSessionCallback, authSession)); + _queryProcessor.AddCallback(DB.Login.AsyncQuery(stmt).WithCallback(HandleAuthSessionCallback, authSession)); } void HandleAuthSessionCallback(AuthSession authSession, SQLResult result) @@ -559,7 +559,7 @@ namespace Game.Network //if (wardenActive) //_worldSession.InitWarden(_sessionKey); - _queryProcessor.AddQuery(_worldSession.LoadPermissionsAsync().WithCallback(LoadSessionPermissionsCallback)); + _queryProcessor.AddCallback(_worldSession.LoadPermissionsAsync().WithCallback(LoadSessionPermissionsCallback)); } void LoadSessionPermissionsCallback(SQLResult result) @@ -587,7 +587,7 @@ namespace Game.Network PreparedStatement stmt = DB.Login.GetPreparedStatement(LoginStatements.SEL_ACCOUNT_INFO_CONTINUED_SESSION); stmt.AddValue(0, accountId); - _queryProcessor.AddQuery(DB.Login.AsyncQuery(stmt).WithCallback(HandleAuthContinuedSessionCallback, authSession)); + _queryProcessor.AddCallback(DB.Login.AsyncQuery(stmt).WithCallback(HandleAuthContinuedSessionCallback, authSession)); } void HandleAuthContinuedSessionCallback(AuthContinuedSession authSession, SQLResult result) @@ -745,7 +745,7 @@ namespace Game.Network ZLib.z_stream _compressionStream; - QueryCallbackProcessor _queryProcessor = new QueryCallbackProcessor(); + AsyncCallbackProcessor _queryProcessor = new AsyncCallbackProcessor(); string _ipCountry; } diff --git a/Source/Game/Server/WorldManager.cs b/Source/Game/Server/WorldManager.cs index 6047565a1..cfff3c9fd 100644 --- a/Source/Game/Server/WorldManager.cs +++ b/Source/Game/Server/WorldManager.cs @@ -1781,7 +1781,7 @@ namespace Game { PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_CHARACTER_COUNT); stmt.AddValue(0, accountId); - _queryProcessor.AddQuery(DB.Characters.AsyncQuery(stmt).WithCallback(_UpdateRealmCharCount)); + _queryProcessor.AddCallback(DB.Characters.AsyncQuery(stmt).WithCallback(_UpdateRealmCharCount)); } void _UpdateRealmCharCount(SQLResult result) @@ -2145,7 +2145,7 @@ namespace Game void ProcessQueryCallbacks() { - _queryProcessor.ProcessReadyQueries(); + _queryProcessor.ProcessReadyCallbacks(); } public void ReloadRBAC() @@ -2324,7 +2324,7 @@ namespace Game ConcurrentQueue> _linkSocketQueue = new ConcurrentQueue>(); - QueryCallbackProcessor _queryProcessor = new QueryCallbackProcessor(); + AsyncCallbackProcessor _queryProcessor = new AsyncCallbackProcessor(); Realm _realm; diff --git a/Source/Game/Server/WorldSession.cs b/Source/Game/Server/WorldSession.cs index 6f3924226..7dabf6bc1 100644 --- a/Source/Game/Server/WorldSession.cs +++ b/Source/Game/Server/WorldSession.cs @@ -631,7 +631,7 @@ namespace Game public ulong GetConnectToInstanceKey() { return _instanceConnectKey.Raw; } - public QueryCallbackProcessor GetQueryProcessor() { return _queryProcessor; } + public AsyncCallbackProcessor GetQueryProcessor() { return _queryProcessor; } void SetLogoutStartTime(long requestTime) { @@ -645,7 +645,8 @@ namespace Game void ProcessQueryCallbacks() { - _queryProcessor.ProcessReadyQueries(); + _queryProcessor.ProcessReadyCallbacks(); + _transactionCallbacks.ProcessReadyCallbacks(); if (_realmAccountLoginCallback != null && _realmAccountLoginCallback.IsCompleted && _accountLoginCallback != null && _accountLoginCallback.IsCompleted) { @@ -662,6 +663,11 @@ namespace Game } } + TransactionCallback AddTransactionCallback(TransactionCallback callback) + { + return _transactionCallbacks.AddCallback(callback); + } + void InitWarden(BigInteger k) { if (_os == "Win") @@ -896,7 +902,8 @@ namespace Game Task> _accountLoginCallback; Task> _charLoginCallback; - QueryCallbackProcessor _queryProcessor = new QueryCallbackProcessor(); + AsyncCallbackProcessor _queryProcessor = new AsyncCallbackProcessor(); + AsyncCallbackProcessor _transactionCallbacks = new AsyncCallbackProcessor(); #endregion }