Core/Instances: Fixed and optimized instance id reuse
This commit is contained in:
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);
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
@@ -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;
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user