Core/Collision: Fix race conditions in mmaps

Fix a race condition in MMapManager happening whenever a map was unloaded. GridUnload enabled was required to trigger the race condition.

(cherry picked from commit aa042e94c2)

Conflicts:
	src/server/collision/Management/MMapManager.cpp
	src/server/collision/Management/MMapManager.h
This commit is contained in:
jackpoz
2015-07-19 23:04:04 +02:00
committed by DDuarte
parent db3a355249
commit d41f87e62a
3 changed files with 61 additions and 22 deletions

View File

@@ -37,11 +37,41 @@ namespace MMAP
// if we had, tiles in MMapData->mmapLoadedTiles, their actual data is lost!
}
void MMapManager::InitializeThreadUnsafe(const std::vector<uint32>& mapIds)
{
// the caller must pass the list of all mapIds that will be used in the VMapManager2 lifetime
for (const uint32& mapId : mapIds)
loadedMMaps.insert(MMapDataSet::value_type(mapId, nullptr));
thread_safe_environment = false;
}
MMapDataSet::const_iterator MMapManager::GetMMapData(uint32 mapId) const
{
// return the iterator if found or end() if not found/NULL
MMapDataSet::const_iterator itr = loadedMMaps.find(mapId);
if (itr != loadedMMaps.cend() && !itr->second)
itr = loadedMMaps.cend();
return itr;
}
bool MMapManager::loadMapData(uint32 mapId)
{
// we already have this map loaded?
if (loadedMMaps.find(mapId) != loadedMMaps.end())
return true;
MMapDataSet::iterator itr = loadedMMaps.find(mapId);
if (itr != loadedMMaps.end())
{
if (itr->second)
return true;
}
else
{
if (thread_safe_environment)
itr = loadedMMaps.insert(MMapDataSet::value_type(mapId, nullptr)).first;
else
ASSERT(false, "Invalid mapId %u passed to MMapManager after startup in thread unsafe environment", mapId);
}
// load and init dtNavMesh - read parameters from file
std::string fileName = Trinity::StringFormat(MAP_FILE_NAME_FORMAT, sWorld->GetDataPath().c_str(), mapId);
@@ -75,7 +105,7 @@ namespace MMAP
// store inside our map list
MMapData* mmap_data = new MMapData(mesh, mapId);
loadedMMaps.insert(std::pair<uint32, MMapData*>(mapId, mmap_data));
itr->second = mmap_data;
return true;
}
@@ -252,14 +282,15 @@ namespace MMAP
bool MMapManager::unloadMap(uint32 mapId, int32 x, int32 y)
{
// check if we have this map loaded
if (loadedMMaps.find(mapId) == loadedMMaps.end())
MMapDataSet::const_iterator itr = GetMMapData(mapId);
if (itr == loadedMMaps.end())
{
// file may not exist, therefore not loaded
TC_LOG_DEBUG("maps", "MMAP:unloadMap: Asked to unload not loaded navmesh map. %04u%02i%02i.mmtile", mapId, x, y);
return false;
}
MMapData* mmap = loadedMMaps[mapId];
MMapData* mmap = itr->second;
// check if we have this tile loaded
uint32 packedGridPos = packTileID(x, y);
@@ -296,7 +327,8 @@ namespace MMAP
bool MMapManager::unloadMap(uint32 mapId)
{
if (loadedMMaps.find(mapId) == loadedMMaps.end())
MMapDataSet::iterator itr = loadedMMaps.find(mapId);
if (itr == loadedMMaps.end() || !itr->second)
{
// file may not exist, therefore not loaded
TC_LOG_DEBUG("maps", "MMAP:unloadMap: Asked to unload not loaded navmesh map %04u", mapId);
@@ -304,7 +336,7 @@ namespace MMAP
}
// unload all tiles from given map
MMapData* mmap = loadedMMaps[mapId];
MMapData* mmap = itr->second;
for (MMapTileSet::iterator i = mmap->loadedTileRefs.begin(); i != mmap->loadedTileRefs.end(); ++i)
{
uint32 x = (i->first >> 16);
@@ -320,7 +352,7 @@ namespace MMAP
}
delete mmap;
loadedMMaps.erase(mapId);
itr->second = nullptr;
TC_LOG_DEBUG("maps", "MMAP:unloadMap: Unloaded %04i.mmap", mapId);
return true;
@@ -329,14 +361,15 @@ namespace MMAP
bool MMapManager::unloadMapInstance(uint32 mapId, uint32 instanceId)
{
// check if we have this map loaded
if (loadedMMaps.find(mapId) == loadedMMaps.end())
MMapDataSet::const_iterator itr = GetMMapData(mapId);
if (itr == loadedMMaps.end())
{
// file may not exist, therefore not loaded
TC_LOG_DEBUG("maps", "MMAP:unloadMapInstance: Asked to unload not loaded navmesh map %04u", mapId);
return false;
}
MMapData* mmap = loadedMMaps[mapId];
MMapData* mmap = itr->second;
if (mmap->navMeshQueries.find(instanceId) == mmap->navMeshQueries.end())
{
TC_LOG_DEBUG("maps", "MMAP:unloadMapInstance: Asked to unload not loaded dtNavMeshQuery mapId %04u instanceId %u", mapId, instanceId);
@@ -354,18 +387,20 @@ namespace MMAP
dtNavMesh const* MMapManager::GetNavMesh(uint32 mapId, TerrainSet swaps)
{
if (loadedMMaps.find(mapId) == loadedMMaps.end())
MMapDataSet::const_iterator itr = GetMMapData(mapId);
if (itr == loadedMMaps.end())
return NULL;
return loadedMMaps[mapId]->GetNavMesh(swaps);
return itr->second->GetNavMesh(swaps);
}
dtNavMeshQuery const* MMapManager::GetNavMeshQuery(uint32 mapId, uint32 instanceId, TerrainSet swaps)
{
if (loadedMMaps.find(mapId) == loadedMMaps.end())
MMapDataSet::const_iterator itr = GetMMapData(mapId);
if (itr == loadedMMaps.end())
return NULL;
MMapData* mmap = loadedMMaps[mapId];
MMapData* mmap = itr->second;
if (mmap->navMeshQueries.find(instanceId) == mmap->navMeshQueries.end())
{
// allocate mesh query

View File

@@ -92,9 +92,10 @@ namespace MMAP
class MMapManager
{
public:
MMapManager() : loadedTiles(0) { }
MMapManager() : loadedTiles(0), thread_safe_environment(true) {}
~MMapManager();
void InitializeThreadUnsafe(const std::vector<uint32>& mapIds);
bool loadMap(const std::string& basePath, uint32 mapId, int32 x, int32 y);
bool unloadMap(uint32 mapId, int32 x, int32 y);
bool unloadMap(uint32 mapId);
@@ -115,8 +116,10 @@ namespace MMAP
bool loadMapData(uint32 mapId);
uint32 packTileID(int32 x, int32 y);
MMapDataSet::const_iterator GetMMapData(uint32 mapId) const;
MMapDataSet loadedMMaps;
uint32 loadedTiles;
bool thread_safe_environment;
PhasedTile* LoadTile(uint32 mapId, int32 x, int32 y);
PhaseTileMap _phaseTiles;

View File

@@ -1471,15 +1471,16 @@ void World::SetInitialWorldSettings()
sSpellMgr->LoadPetFamilySpellsStore();
if (VMAP::VMapManager2* vmmgr2 = dynamic_cast<VMAP::VMapManager2*>(VMAP::VMapFactory::createOrGetVMapManager()))
{
std::vector<uint32> mapIds;
for (uint32 mapId = 0; mapId < sMapStore.GetNumRows(); mapId++)
if (sMapStore.LookupEntry(mapId))
mapIds.push_back(mapId);
std::vector<uint32> mapIds;
for (uint32 mapId = 0; mapId < sMapStore.GetNumRows(); mapId++)
if (sMapStore.LookupEntry(mapId))
mapIds.push_back(mapId);
if (VMAP::VMapManager2* vmmgr2 = dynamic_cast<VMAP::VMapManager2*>(VMAP::VMapFactory::createOrGetVMapManager()))
vmmgr2->InitializeThreadUnsafe(mapIds);
}
MMAP::MMapManager* mmmgr = MMAP::MMapFactory::createOrGetMMapManager();
mmmgr->InitializeThreadUnsafe(mapIds);
TC_LOG_INFO("server.loading", "Loading SpellInfo store...");
sSpellMgr->LoadSpellInfoStore();