Core/Instances: Fixed and optimized instance id reuse

(cherry picked from commit 2639056071)
This commit is contained in:
Shauren
2017-06-05 19:25:42 +02:00
committed by Carbenium
parent f4ac8146b6
commit fbdf8784a5
3 changed files with 30 additions and 46 deletions

View File

@@ -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;
}