Core/Instances: Fixed and optimized instance id reuse

This commit is contained in:
Shauren authored and Aokromes committed 2017-06-06 08:00:10 +02:00
1 parent bc1887c5df
commit 900a2da03d
3 files changed
+30 -46

No files matched your search

@@ -323,11 +323,6 @@ void InstanceSaveManager::LoadResetTimes()
uint32 instanceId = fields[0].GetUInt32(); 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 // Mark instance id as being used
sMapMgr->RegisterInstanceId(instanceId); sMapMgr->RegisterInstanceId(instanceId);
+27 -36
View File
@@ -310,55 +310,48 @@ void MapManager::InitInstanceIds()
{ {
_nextInstanceId = 1; _nextInstanceId = 1;
QueryResult result = CharacterDatabase.Query("SELECT MAX(id) FROM instance"); if (QueryResult result = CharacterDatabase.Query("SELECT IFNULL(MAX(id), 0) FROM instance"))
if (result) _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
uint32 maxId = (*result)[0].GetUInt32(); _freeInstanceIds.resize(_nextInstanceId + 1, true);
// Resize to multiples of 32 (vector<bool> allocates memory the same way) // never allow 0 id
_instanceIds.resize((maxId / 32) * 32 + (maxId % 32 > 0 ? 32 : 0)); _freeInstanceIds[0] = false;
}
} }
void MapManager::RegisterInstanceId(uint32 instanceId) void MapManager::RegisterInstanceId(uint32 instanceId)
{ {
// Allocation and sizing was done in InitInstanceIds() // 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 MapManager::GenerateInstanceId()
{ {
uint32 newInstanceId = _nextInstanceId; if (_nextInstanceId == 0xFFFFFFFF)
// 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)
{ {
TC_LOG_ERROR("maps", "Instance ID overflow!! Can't continue, shutting down server. "); TC_LOG_ERROR("maps", "Instance ID overflow!! Can't continue, shutting down server. ");
World::StopNow(ERROR_EXIT_CODE); World::StopNow(ERROR_EXIT_CODE);
return _nextInstanceId;
} }
// Allocate space if necessary uint32 newInstanceId = _nextInstanceId;
if (newInstanceId >= uint32(_instanceIds.size())) 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 _nextInstanceId = uint32(_freeInstanceIds.size());
if (_instanceIds.size() < _instanceIds.capacity()) _freeInstanceIds.push_back(true);
{
_instanceIds.resize(_instanceIds.capacity());
}
else
_instanceIds.resize((newInstanceId / 32) * 32 + (newInstanceId % 32 > 0 ? 32 : 0));
} }
else
_instanceIds[newInstanceId] = true; _nextInstanceId = uint32(nextFreedId);
return newInstanceId; return newInstanceId;
} }
@@ -366,9 +359,7 @@ uint32 MapManager::GenerateInstanceId()
void MapManager::FreeInstanceId(uint32 instanceId) 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 freed instance id is lower than the next id available for new instances, use the freed one instead
if (instanceId < _nextInstanceId) _nextInstanceId = std::min(instanceId, _nextInstanceId);
SetNextInstanceId(instanceId); _freeInstanceIds[instanceId] = true;
_instanceIds[instanceId] = false;
sAchievementMgr->OnInstanceDestroyed(instanceId); sAchievementMgr->OnInstanceDestroyed(instanceId);
} }
+3 -5
View File
@@ -24,6 +24,7 @@
#include "MapInstanced.h" #include "MapInstanced.h"
#include "GridStates.h" #include "GridStates.h"
#include "MapUpdater.h" #include "MapUpdater.h"
#include <boost/dynamic_bitset.hpp>
class Transport; class Transport;
struct TransportCreatureProto; struct TransportCreatureProto;
@@ -115,9 +116,6 @@ class TC_GAME_API MapManager
void RegisterInstanceId(uint32 instanceId); void RegisterInstanceId(uint32 instanceId);
void FreeInstanceId(uint32 instanceId); void FreeInstanceId(uint32 instanceId);
uint32 GetNextInstanceId() const { return _nextInstanceId; };
void SetNextInstanceId(uint32 nextInstanceId) { _nextInstanceId = nextInstanceId; };
MapUpdater * GetMapUpdater() { return &m_updater; } MapUpdater * GetMapUpdater() { return &m_updater; }
template<typename Worker> template<typename Worker>
@@ -133,7 +131,7 @@ class TC_GAME_API MapManager
private: private:
typedef std::unordered_map<uint32, Map*> MapMapType; typedef std::unordered_map<uint32, Map*> MapMapType;
typedef std::vector<bool> InstanceIds; typedef boost::dynamic_bitset<size_t> InstanceIds;
MapManager(); MapManager();
~MapManager(); ~MapManager();
@@ -152,7 +150,7 @@ class TC_GAME_API MapManager
MapMapType i_maps; MapMapType i_maps;
IntervalTimer i_timer; IntervalTimer i_timer;
InstanceIds _instanceIds; InstanceIds _freeInstanceIds;
uint32 _nextInstanceId; uint32 _nextInstanceId;
MapUpdater m_updater; MapUpdater m_updater;