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.
This commit is contained in:
jackpoz
2015-07-19 23:04:04 +02:00
parent 3c4484d782
commit aa042e94c2
3 changed files with 61 additions and 24 deletions

View File

@@ -32,11 +32,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
uint32 pathLen = sWorld->GetDataPath().length() + strlen("mmaps/%03i.mmap")+1;
@@ -79,7 +109,7 @@ namespace MMAP
MMapData* mmap_data = new MMapData(mesh);
mmap_data->mmapLoadedTiles.clear();
loadedMMaps.insert(std::pair<uint32, MMapData*>(mapId, mmap_data));
itr->second = mmap_data;
return true;
}
@@ -165,21 +195,20 @@ namespace MMAP
dtFree(data);
return false;
}
return false;
}
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. %03u%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);
@@ -214,7 +243,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 %03u", mapId);
@@ -222,7 +252,7 @@ namespace MMAP
}
// unload all tiles from given map
MMapData* mmap = loadedMMaps[mapId];
MMapData* mmap = itr->second;
for (MMapTileSet::iterator i = mmap->mmapLoadedTiles.begin(); i != mmap->mmapLoadedTiles.end(); ++i)
{
uint32 x = (i->first >> 16);
@@ -237,7 +267,7 @@ namespace MMAP
}
delete mmap;
loadedMMaps.erase(mapId);
itr->second = nullptr;
TC_LOG_DEBUG("maps", "MMAP:unloadMap: Unloaded %03i.mmap", mapId);
return true;
@@ -246,14 +276,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 %03u", 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 %03u instanceId %u", mapId, instanceId);
@@ -271,18 +302,20 @@ namespace MMAP
dtNavMesh const* MMapManager::GetNavMesh(uint32 mapId)
{
if (loadedMMaps.find(mapId) == loadedMMaps.end())
MMapDataSet::const_iterator itr = GetMMapData(mapId);
if (itr == loadedMMaps.end())
return NULL;
return loadedMMaps[mapId]->navMesh;
return itr->second->navMesh;
}
dtNavMeshQuery const* MMapManager::GetNavMeshQuery(uint32 mapId, uint32 instanceId)
{
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

@@ -60,9 +60,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);
@@ -78,8 +79,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;
};
}

View File

@@ -1375,15 +1375,16 @@ void World::SetInitialWorldSettings()
LoadDBCStores(m_dataPath);
DetectDBCLang();
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();