Core/Instances: Fixed and optimized instance id reuse

Port From (https://github.com/TrinityCore/TrinityCore/commit/fbdf8784a5c03dfcb575ef7b760a62d0d9d2acc1)
This commit is contained in:
hondacrx
2020-07-22 14:07:02 -04:00
parent d1ebddbe95
commit df0ee4462c
2 changed files with 40 additions and 22 deletions
@@ -199,11 +199,6 @@ namespace Game.Maps
{ {
uint instanceId = result.Read<uint>(0); uint instanceId = result.Read<uint>(0);
// 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 (Global.MapMgr.GetNextInstanceId() == instanceId)
Global.MapMgr.SetNextInstanceId(instanceId + 1);
// Mark instance id as being used // Mark instance id as being used
Global.MapMgr.RegisterInstanceId(instanceId); Global.MapMgr.RegisterInstanceId(instanceId);
long resettime = result.Read<long>(3); long resettime = result.Read<long>(3);
+39 -16
View File
@@ -16,12 +16,13 @@
*/ */
using Framework.Constants; using Framework.Constants;
using Framework.Database;
using Game.DataStorage; using Game.DataStorage;
using Game.Groups; using Game.Groups;
using Game.Maps; using Game.Maps;
using System; using System;
using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
namespace Game.Entities namespace Game.Entities
{ {
@@ -321,35 +322,59 @@ namespace Game.Entities
public void InitInstanceIds() public void InitInstanceIds()
{ {
_nextInstanceId = 1; _nextInstanceId = 1;
SQLResult result = DB.Characters.Query("SELECT IFNULL(MAX(id), 0) FROM instance");
if (!result.IsEmpty())
_freeInstanceIds = new BitSet(result.Read<int>(0) + 2, true); // make space for one extra to be able to access [_nextInstanceId] index in case all slots are taken
else
_freeInstanceIds = new BitSet((int)_nextInstanceId + 1, true);
// never allow 0 id
_freeInstanceIds[0] = false;
} }
public void RegisterInstanceId(uint instanceId) public void RegisterInstanceId(uint instanceId)
{ {
// Allocation and sizing was done in InitInstanceIds() _freeInstanceIds[(int)instanceId] = false;
_instanceIds[instanceId] = true;
// 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;
} }
public uint GenerateInstanceId() public uint GenerateInstanceId()
{ {
if (_nextInstanceId == 0xFFFFFFFF)
{
Log.outError(LogFilter.Maps, "Instance ID overflow!! Can't continue, shutting down server. ");
Global.WorldMgr.StopNow();
return _nextInstanceId;
}
uint newInstanceId = _nextInstanceId; uint newInstanceId = _nextInstanceId;
Cypher.Assert(newInstanceId < _freeInstanceIds.Length);
_freeInstanceIds[(int)newInstanceId] = false;
// Find the lowest available id starting from the current NextInstanceId (which should be the lowest according to the logic in FreeInstanceId() // Find the lowest available id starting from the current NextInstanceId (which should be the lowest according to the logic in FreeInstanceId()
for (uint i = ++_nextInstanceId; i < 0xFFFFFFFF; ++i) int nextFreeId = -1;
for (var i = (int)_nextInstanceId++; i < _freeInstanceIds.Length; i++)
{ {
if ((i < _instanceIds.Count && !_instanceIds[i]) || i >= _instanceIds.Count) if (_freeInstanceIds[i])
{ {
_nextInstanceId = i; nextFreeId = i;
break; break;
} }
} }
if (newInstanceId == _nextInstanceId) if (nextFreeId == -1)
{ {
Log.outError(LogFilter.Maps, "Instance ID overflow!! Can't continue, shutting down server. "); _nextInstanceId = (uint)_freeInstanceIds.Length;
Global.WorldMgr.StopNow(); _freeInstanceIds.Length += 1;
_freeInstanceIds[(int)_nextInstanceId] = true;
} }
else
_instanceIds[newInstanceId] = true; _nextInstanceId = (uint)nextFreeId;
return newInstanceId; return newInstanceId;
} }
@@ -357,10 +382,8 @@ namespace Game.Entities
public void FreeInstanceId(uint instanceId) public void FreeInstanceId(uint 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 = Math.Min(instanceId, _nextInstanceId);
SetNextInstanceId(instanceId); _freeInstanceIds[(int)instanceId] = true;
_instanceIds[instanceId] = false;
} }
public void SetGridCleanUpDelay(uint t) public void SetGridCleanUpDelay(uint t)
@@ -455,7 +478,7 @@ namespace Game.Entities
IntervalTimer i_timer = new IntervalTimer(); IntervalTimer i_timer = new IntervalTimer();
object _mapsLock= new object(); object _mapsLock= new object();
uint i_gridCleanUpDelay; uint i_gridCleanUpDelay;
Dictionary<uint, bool> _instanceIds = new Dictionary<uint, bool>(); BitSet _freeInstanceIds;
uint _nextInstanceId; uint _nextInstanceId;
MapUpdater m_updater; MapUpdater m_updater;
uint _scheduledScripts; uint _scheduledScripts;