diff options
author | Shauren <shauren.trinity@gmail.com> | 2017-06-05 19:25:42 +0200 |
---|---|---|
committer | Carbenium <carbenium@outlook.com> | 2020-07-16 21:47:27 +0200 |
commit | fbdf8784a5c03dfcb575ef7b760a62d0d9d2acc1 (patch) | |
tree | 481382d77cf0f3794f1b9b9d9032db98e9fcd988 | |
parent | f4ac8146b6fb76fd80f525dbb8b14706fa080f98 (diff) |
Core/Instances: Fixed and optimized instance id reuse
(cherry picked from commit 2639056071597edfdf74b31a16ce644610a1b6d9)
-rw-r--r-- | src/server/game/Instances/InstanceSaveMgr.cpp | 5 | ||||
-rw-r--r-- | src/server/game/Maps/MapManager.cpp | 63 | ||||
-rw-r--r-- | src/server/game/Maps/MapManager.h | 8 |
3 files changed, 30 insertions, 46 deletions
diff --git a/src/server/game/Instances/InstanceSaveMgr.cpp b/src/server/game/Instances/InstanceSaveMgr.cpp index f04ae452c0b..d8681c08f65 100644 --- a/src/server/game/Instances/InstanceSaveMgr.cpp +++ b/src/server/game/Instances/InstanceSaveMgr.cpp @@ -337,11 +337,6 @@ void InstanceSaveManager::LoadResetTimes() uint32 instanceId = fields[0].GetUInt32(); - // Instances are pulled in ascending order from db and nextInstanceId is initialized with 1, - // so if the instance id is used, increment until we find the first unused one for a potential new instance - if (sMapMgr->GetNextInstanceId() == instanceId) - sMapMgr->SetNextInstanceId(instanceId + 1); - // Mark instance id as being used sMapMgr->RegisterInstanceId(instanceId); diff --git a/src/server/game/Maps/MapManager.cpp b/src/server/game/Maps/MapManager.cpp index 6a441a21f9f..4125b574b83 100644 --- a/src/server/game/Maps/MapManager.cpp +++ b/src/server/game/Maps/MapManager.cpp @@ -337,55 +337,48 @@ void MapManager::InitInstanceIds() { _nextInstanceId = 1; - QueryResult result = CharacterDatabase.Query("SELECT MAX(id) FROM instance"); - if (result) - { - uint32 maxId = (*result)[0].GetUInt32(); + if (QueryResult result = CharacterDatabase.Query("SELECT IFNULL(MAX(id), 0) FROM instance")) + _freeInstanceIds.resize((*result)[0].GetUInt32() + 2, true); // make space for one extra to be able to access [_nextInstanceId] index in case all slots are taken + else + _freeInstanceIds.resize(_nextInstanceId + 1, true); - // Resize to multiples of 32 (vector<bool> allocates memory the same way) - _instanceIds.resize((maxId / 32) * 32 + (maxId % 32 > 0 ? 32 : 0)); - } + // never allow 0 id + _freeInstanceIds[0] = false; } void MapManager::RegisterInstanceId(uint32 instanceId) { // Allocation and sizing was done in InitInstanceIds() - _instanceIds[instanceId] = true; + _freeInstanceIds[instanceId] = false; + + // Instances are pulled in ascending order from db and nextInstanceId is initialized with 1, + // so if the instance id is used, increment until we find the first unused one for a potential new instance + if (_nextInstanceId == instanceId) + ++_nextInstanceId; } uint32 MapManager::GenerateInstanceId() { - uint32 newInstanceId = _nextInstanceId; - - // Find the lowest available id starting from the current NextInstanceId (which should be the lowest according to the logic in FreeInstanceId() - for (uint32 i = ++_nextInstanceId; i < 0xFFFFFFFF; ++i) - { - if ((i < _instanceIds.size() && !_instanceIds[i]) || i >= _instanceIds.size()) - { - _nextInstanceId = i; - break; - } - } - - if (newInstanceId == _nextInstanceId) + if (_nextInstanceId == 0xFFFFFFFF) { TC_LOG_ERROR("maps", "Instance ID overflow!! Can't continue, shutting down server. "); World::StopNow(ERROR_EXIT_CODE); + return _nextInstanceId; } - // Allocate space if necessary - if (newInstanceId >= uint32(_instanceIds.size())) + uint32 newInstanceId = _nextInstanceId; + ASSERT(newInstanceId < _freeInstanceIds.size()); + _freeInstanceIds[newInstanceId] = false; + + // Find the lowest available id starting from the current NextInstanceId (which should be the lowest according to the logic in FreeInstanceId() + size_t nextFreedId = _freeInstanceIds.find_next(_nextInstanceId++); + if (nextFreedId == InstanceIds::npos) { - // Due to the odd memory allocation behavior of vector<bool> we match size to capacity before triggering a new allocation - if (_instanceIds.size() < _instanceIds.capacity()) - { - _instanceIds.resize(_instanceIds.capacity()); - } - else - _instanceIds.resize((newInstanceId / 32) * 32 + (newInstanceId % 32 > 0 ? 32 : 0)); + _nextInstanceId = uint32(_freeInstanceIds.size()); + _freeInstanceIds.push_back(true); } - - _instanceIds[newInstanceId] = true; + else + _nextInstanceId = uint32(nextFreedId); return newInstanceId; } @@ -393,8 +386,6 @@ uint32 MapManager::GenerateInstanceId() void MapManager::FreeInstanceId(uint32 instanceId) { // If freed instance id is lower than the next id available for new instances, use the freed one instead - if (instanceId < _nextInstanceId) - SetNextInstanceId(instanceId); - - _instanceIds[instanceId] = false; + _nextInstanceId = std::min(instanceId, _nextInstanceId); + _freeInstanceIds[instanceId] = true; } diff --git a/src/server/game/Maps/MapManager.h b/src/server/game/Maps/MapManager.h index 204a81e2182..68b08ebc7a4 100644 --- a/src/server/game/Maps/MapManager.h +++ b/src/server/game/Maps/MapManager.h @@ -23,6 +23,7 @@ #include "MapInstanced.h" #include "GridStates.h" #include "MapUpdater.h" +#include <boost/dynamic_bitset.hpp> class PhaseShift; class Transport; @@ -116,9 +117,6 @@ class TC_GAME_API MapManager void RegisterInstanceId(uint32 instanceId); void FreeInstanceId(uint32 instanceId); - uint32 GetNextInstanceId() const { return _nextInstanceId; }; - void SetNextInstanceId(uint32 nextInstanceId) { _nextInstanceId = nextInstanceId; }; - MapUpdater * GetMapUpdater() { return &m_updater; } template<typename Worker> @@ -134,7 +132,7 @@ class TC_GAME_API MapManager private: typedef std::unordered_map<uint32, Map*> MapMapType; - typedef std::vector<bool> InstanceIds; + typedef boost::dynamic_bitset<size_t> InstanceIds; MapManager(); ~MapManager(); @@ -155,7 +153,7 @@ class TC_GAME_API MapManager MapMapType i_maps; IntervalTimer i_timer; - InstanceIds _instanceIds; + InstanceIds _freeInstanceIds; uint32 _nextInstanceId; MapUpdater m_updater; |