diff options
author | jackpoz <giacomopoz@gmail.com> | 2015-07-19 23:04:04 +0200 |
---|---|---|
committer | DDuarte <dnpd.dd@gmail.com> | 2015-07-21 19:01:44 +0100 |
commit | d41f87e62abef6fa4b0dc23274023d91bdc005d8 (patch) | |
tree | 03dbd38681c16d41ecef8dc30165d8d5fe4a127d | |
parent | db3a35524999c8af1023896be44da48b19607a73 (diff) |
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 aa042e94c2f76e5735a8f745c3fcb7dd54cf6c0b)
Conflicts:
src/server/collision/Management/MMapManager.cpp
src/server/collision/Management/MMapManager.h
-rw-r--r-- | src/server/collision/Management/MMapManager.cpp | 63 | ||||
-rw-r--r-- | src/server/collision/Management/MMapManager.h | 5 | ||||
-rw-r--r-- | src/server/game/World/World.cpp | 15 |
3 files changed, 61 insertions, 22 deletions
diff --git a/src/server/collision/Management/MMapManager.cpp b/src/server/collision/Management/MMapManager.cpp index e0b1ed3b161..0b9c1b325b7 100644 --- a/src/server/collision/Management/MMapManager.cpp +++ b/src/server/collision/Management/MMapManager.cpp @@ -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 diff --git a/src/server/collision/Management/MMapManager.h b/src/server/collision/Management/MMapManager.h index b7356716a9d..2b3818601af 100644 --- a/src/server/collision/Management/MMapManager.h +++ b/src/server/collision/Management/MMapManager.h @@ -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; diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp index 948729c6d70..2fdb8a52aa2 100644 --- a/src/server/game/World/World.cpp +++ b/src/server/game/World/World.cpp @@ -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(); |