From 740d34d9e70ef1b7ba5acc05fcdd8e0b2d66efc3 Mon Sep 17 00:00:00 2001
From: Rye Mutt <rye@alchemyviewer.org>
Date: Tue, 20 Dec 2022 20:45:52 -0500
Subject: [PATCH] Clean up and crash fixes to mesh repo

---
 indra/newview/llcontrolavatar.cpp  |   2 +-
 indra/newview/llmeshrepository.cpp | 497 ++++++++++-------------------
 indra/newview/llmeshrepository.h   |  17 +-
 indra/newview/llspatialpartition.h |   2 +-
 indra/newview/llvovolume.cpp       |  38 ++-
 indra/newview/llvovolume.h         |  12 +-
 6 files changed, 219 insertions(+), 349 deletions(-)

diff --git a/indra/newview/llcontrolavatar.cpp b/indra/newview/llcontrolavatar.cpp
index f04b487d120..5523ca494d6 100644
--- a/indra/newview/llcontrolavatar.cpp
+++ b/indra/newview/llcontrolavatar.cpp
@@ -235,7 +235,7 @@ void LLControlAvatar::matchVolumeTransform()
 #define MATCH_BIND_SHAPE
 #ifdef MATCH_BIND_SHAPE
             // MAINT-8671 - based on a patch from Beq Janus
-	        const LLMeshSkinInfo* skin_info = mRootVolp->getSkinInfo();
+	        LLConstPointer<LLMeshSkinInfo> skin_info = mRootVolp->getSkinInfo();
 			if (skin_info)
 			{
 #ifdef SHOW_DEBUG
diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp
index a8a61170bd6..1a88cdd720b 100644
--- a/indra/newview/llmeshrepository.cpp
+++ b/indra/newview/llmeshrepository.cpp
@@ -1170,8 +1170,9 @@ void LLMeshRepoThread::lockAndLoadMeshLOD(const LLVolumeParams& mesh_params, S32
 
 void LLMeshRepoThread::loadMeshLOD(const LLVolumeParams& mesh_params, S32 lod)
 { //could be called from any thread
+	const LLUUID& mesh_id = mesh_params.getSculptID();
 	LLMutexLock header_lock(mHeaderMutex);
-	mesh_header_map::iterator iter = mMeshHeader.find(mesh_params.getSculptID());
+	mesh_header_map::iterator iter = mMeshHeader.find(mesh_id);
 	if (iter != mMeshHeader.end())
 	{ //if we have the header, request LOD byte range
 		header_lock.unlock();
@@ -1186,11 +1187,8 @@ void LLMeshRepoThread::loadMeshLOD(const LLVolumeParams& mesh_params, S32 lod)
 	else
 	{ 
 		header_lock.unlock();
-
 		HeaderRequest req(mesh_params);
 
-		const LLUUID& mesh_id = mesh_params.getSculptID();
-
 		LLMutexLock lock(mMutex);
 		pending_lod_map::iterator pending = mPendingLOD.find(mesh_id);
 
@@ -1325,101 +1323,104 @@ LLCore::HttpHandle LLMeshRepoThread::getByteRange(const std::string & url, int l
 	return handle;
 }
 
-
-bool LLMeshRepoThread::fetchMeshSkinInfo(const LLUUID& mesh_id, bool can_retry)
-{
-	
+bool LLMeshRepoThread::getMeshHeaderInfo(const LLUUID& mesh_id, const char* block_name, MeshHeaderInfo& info)
+{	//protected by mMutex
 	if (!mHeaderMutex)
 	{
 		return false;
 	}
 
-	mHeaderMutex->lock();
+	LLMutexLock lock(mHeaderMutex);
+
+	++LLMeshRepository::sMeshRequestCount;
 
 	auto header_it = mMeshHeader.find(mesh_id);
 	if (header_it == mMeshHeader.end())
 	{ //we have no header info for this mesh, do nothing
-		mHeaderMutex->unlock();
 		return false;
 	}
 
-	++LLMeshRepository::sMeshRequestCount;
-	bool ret = true;
-	U32 header_size = header_it->second.first;
-	
-	if (header_size > 0)
+	if ((info.mHeaderSize = header_it->second.first) > 0)
 	{
-		const auto& header = header_it->second.second;
-		S32 version = header["version"].asInteger();
-		S32 offset = header_size + header["skin"]["offset"].asInteger();
-		S32 size = header["skin"]["size"].asInteger();
+		const LLSD& header = header_it->second.second;
+		const LLSD& block = header[block_name];
+		info.mVersion = header["version"].asInteger();
+		info.mOffset = info.mHeaderSize + block["offset"].asInteger();
+		info.mSize = block["size"].asInteger();
+	}
+	return true;
+}
 
-		mHeaderMutex->unlock();
+bool LLMeshRepoThread::loadInfoFromFilesystem(const LLUUID& mesh_id, MeshHeaderInfo& info, boost::function<bool(const LLUUID&, U8*, S32)> fn)
+{
+	//check cache for mesh skin info
+	LLFileSystem file(mesh_id, LLAssetType::AT_MESH);
+	if (file.getSize() >= info.mOffset + info.mSize)
+	{
+		auto buffer = std::make_unique<U8[]>(info.mSize);
+		if (!buffer)
+		{
+			LL_WARNS_ONCE(LOG_MESH) << "Failed to allocate memory for mesh data load, size: " << info.mSize << LL_ENDL;
+			return false;
+		}
+		LLMeshRepository::sCacheBytesRead += info.mSize;
+		++LLMeshRepository::sCacheReads;
+		file.seek(info.mOffset);
+		file.read(buffer.get(), info.mSize);
 
-		if (version <= MAX_MESH_VERSION && offset >= 0 && size > 0)
+		//make sure buffer isn't all 0's by checking the first 1KB (reserved block but not written)
+		bool zero = true;
+		for (S32 i = 0; i < llmin(info.mSize, S32(1024)) && zero; ++i)
 		{
-			//check cache for mesh skin info
-			LLFileSystem file(mesh_id, LLAssetType::AT_MESH, LLFileSystem::READ);
-			if (file.open() && file.getSize() >= offset+size)
-			{
-				U8* buffer = new(std::nothrow) U8[size];
-				if (!buffer)
-				{
-					LL_WARNS_ONCE(LOG_MESH) << "Failed to allocate memory for skin info, size: " << size << LL_ENDL;
-					return false;
-				}
-				LLMeshRepository::sCacheBytesRead += size;
-				++LLMeshRepository::sCacheReads;
-				file.seek(offset);
-				file.read(buffer, size);
-				file.close();
+			zero = buffer[i] > 0 ? false : true;
+		}
 
-				//make sure buffer isn't all 0's by checking the first 1KB (reserved block but not written)
-				bool zero = true;
-				for (S32 i = 0; i < llmin(size, 1024) && zero; ++i)
-				{
-					zero = buffer[i] > 0 ? false : true;
-				}
+		if (!zero)
+		{ //attempt to parse
+			if (fn(mesh_id, buffer.get(), info.mSize))
+			{
+				return true;
+			}
+		}
+	}
+	return false;
+}
 
-				if (!zero)
-				{ //attempt to parse
-					if (skinInfoReceived(mesh_id, buffer, size))
-					{						
-						delete[] buffer;
-						return true;
-					}
-				}
+bool LLMeshRepoThread::fetchMeshSkinInfo(const LLUUID& mesh_id, bool can_retry)
+{
+	MeshHeaderInfo info;
+	if (!getMeshHeaderInfo(mesh_id, "skin", info))
+	{
+		return false;
+	}
 
-				delete[] buffer;
-			}
+	if (info.mHeaderSize > 0 && info.mVersion <= MAX_MESH_VERSION && info.mOffset >= 0 && info.mSize > 0)
+	{
+		//check cache for mesh skin info
+		if (loadInfoFromFilesystem(mesh_id, info, boost::bind(&LLMeshRepoThread::skinInfoReceived, this, _1, _2, _3)))
+			return true;
 
-			//reading from cache failed for whatever reason, fetch from sim
-			std::string http_url;
-			int legacy_cap_version(0);
-			constructUrl(mesh_id, &http_url, &legacy_cap_version);
+		//reading from cache failed for whatever reason, fetch from sim
+		std::string http_url;
+		int legacy_cap_version(0);
+		constructUrl(mesh_id, &http_url, &legacy_cap_version);
 
-			if (!http_url.empty())
+		if (!http_url.empty())
+		{
+            auto handler = std::make_shared<LLMeshSkinInfoHandler>(mesh_id, info.mOffset, info.mSize);
+			LLCore::HttpHandle handle = getByteRange(http_url, legacy_cap_version, info.mOffset, info.mSize, handler);
+			if (LLCORE_HTTP_HANDLE_INVALID == handle)
 			{
-                auto handler = std::make_shared<LLMeshSkinInfoHandler>(mesh_id, offset, size);
-				LLCore::HttpHandle handle = getByteRange(http_url, legacy_cap_version, offset, size, handler);
-				if (LLCORE_HTTP_HANDLE_INVALID == handle)
-				{
-					LL_WARNS(LOG_MESH) << "HTTP GET request failed for skin info on mesh " << mID
-									   << ".  Reason:  " << mHttpStatus.toString()
-									   << " (" << mHttpStatus.toTerseString() << ")"
-									   << LL_ENDL;
-					ret = false;
-				}
-				else if(can_retry)
-				{
-					handler->mHttpHandle = handle;
-					mHttpRequestSet.emplace(std::move(handler));
-				}
-				else
-				{
-					LLMutexLock locker(mMutex);
-					mSkinUnavailableQ.emplace_back(mesh_id);
-				}
+				LL_WARNS(LOG_MESH) << "HTTP GET request failed for skin info on mesh " << mID
+								   << ".  Reason:  " << mHttpStatus.toString()
+								   << " (" << mHttpStatus.toTerseString() << ")"
+								   << LL_ENDL;
+				return false;
+			}
+			else if (can_retry)
+			{
+				handler->mHttpHandle = handle;
+				mHttpRequestSet.emplace(std::move(handler));
 			}
 			else
 			{
@@ -1434,180 +1435,72 @@ bool LLMeshRepoThread::fetchMeshSkinInfo(const LLUUID& mesh_id, bool can_retry)
 		}
 	}
 	else
-	{	
-		mHeaderMutex->unlock();
+	{
+		LLMutexLock locker(mMutex);
+		mSkinUnavailableQ.emplace_back(mesh_id);
 	}
 
 	//early out was not hit, effectively fetched
-	return ret;
+	return true;
 }
 
 bool LLMeshRepoThread::fetchMeshDecomposition(const LLUUID& mesh_id)
 {
-	if (!mHeaderMutex)
+	MeshHeaderInfo info;
+	if (!getMeshHeaderInfo(mesh_id, "physics_convex", info))
 	{
 		return false;
 	}
 
-	mHeaderMutex->lock();
-
-	auto header_it = mMeshHeader.find(mesh_id);
-	if (header_it == mMeshHeader.end())
-	{ //we have no header info for this mesh, do nothing
-		mHeaderMutex->unlock();
-		return false;
-	}
-
-	++LLMeshRepository::sMeshRequestCount;
-	U32 header_size = header_it->second.first;
-	bool ret = true;
-	
-	if (header_size > 0)
+	if (info.mHeaderSize > 0 && info.mVersion <= MAX_MESH_VERSION && info.mOffset >= 0 && info.mSize > 0)
 	{
-		const auto& header = header_it->second.second;
-		S32 version = header["version"].asInteger();
-		S32 offset = header_size + header["physics_convex"]["offset"].asInteger();
-		S32 size = header["physics_convex"]["size"].asInteger();
+		//check cache for mesh physics info
+		if (loadInfoFromFilesystem(mesh_id, info, boost::bind(&LLMeshRepoThread::decompositionReceived, this, _1, _2, _3)))
+			return true;
 
-		mHeaderMutex->unlock();
+		//reading from cache failed for whatever reason, fetch from sim
+		std::string http_url;
+		int legacy_cap_version(0);
+		constructUrl(mesh_id, &http_url, &legacy_cap_version);
 
-		if (version <= MAX_MESH_VERSION && offset >= 0 && size > 0)
+		if (!http_url.empty())
 		{
-			//check cache for mesh skin info
-			LLFileSystem file(mesh_id, LLAssetType::AT_MESH, LLFileSystem::READ);
-			if (file.open() && file.getSize() >= offset+size)
+            auto handler = std::make_shared<LLMeshDecompositionHandler>(mesh_id, info.mOffset, info.mSize);
+			LLCore::HttpHandle handle = getByteRange(http_url, legacy_cap_version, info.mOffset, info.mSize, handler);
+			if (LLCORE_HTTP_HANDLE_INVALID == handle)
 			{
-				U8* buffer = new(std::nothrow) U8[size];
-				if (!buffer)
-				{
-					LL_WARNS_ONCE(LOG_MESH) << "Failed to allocate memory for mesh decomposition, size: " << size << LL_ENDL;
-					return false;
-				}
-				LLMeshRepository::sCacheBytesRead += size;
-				++LLMeshRepository::sCacheReads;
-
-				file.seek(offset);
-				file.read(buffer, size);
-				file.close();
-
-				//make sure buffer isn't all 0's by checking the first 1KB (reserved block but not written)
-				bool zero = true;
-				for (S32 i = 0; i < llmin(size, 1024) && zero; ++i)
-				{
-					zero = buffer[i] > 0 ? false : true;
-				}
-
-				if (!zero)
-				{ //attempt to parse
-					if (decompositionReceived(mesh_id, buffer, size))
-					{
-						delete[] buffer;
-						return true;
-					}
-				}
-
-				delete[] buffer;
+				LL_WARNS(LOG_MESH) << "HTTP GET request failed for decomposition mesh " << mID
+								   << ".  Reason:  " << mHttpStatus.toString()
+								   << " (" << mHttpStatus.toTerseString() << ")"
+								   << LL_ENDL;
+				return false;
 			}
-
-			//reading from cache failed for whatever reason, fetch from sim
-			std::string http_url;
-			int legacy_cap_version(0);
-			constructUrl(mesh_id, &http_url, &legacy_cap_version);
-			
-			if (!http_url.empty())
+			else
 			{
-                auto handler = std::make_shared<LLMeshDecompositionHandler>(mesh_id, offset, size);
-				LLCore::HttpHandle handle = getByteRange(http_url, legacy_cap_version, offset, size, handler);
-				if (LLCORE_HTTP_HANDLE_INVALID == handle)
-				{
-					LL_WARNS(LOG_MESH) << "HTTP GET request failed for decomposition mesh " << mID
-									   << ".  Reason:  " << mHttpStatus.toString()
-									   << " (" << mHttpStatus.toTerseString() << ")"
-									   << LL_ENDL;
-					ret = false;
-				}
-				else
-				{
-					handler->mHttpHandle = handle;
-					mHttpRequestSet.insert(handler);
-				}
+				handler->mHttpHandle = handle;
+				mHttpRequestSet.insert(handler);
 			}
 		}
 	}
-	else
-	{	
-		mHeaderMutex->unlock();
-	}
 
 	//early out was not hit, effectively fetched
-	return ret;
+	return true;
 }
 
 bool LLMeshRepoThread::fetchMeshPhysicsShape(const LLUUID& mesh_id)
 {
-	if (!mHeaderMutex)
+	MeshHeaderInfo info;
+	if (!getMeshHeaderInfo(mesh_id, "physics_mesh", info))
 	{
 		return false;
 	}
 
-	mHeaderMutex->lock();
-
-	auto header_it = mMeshHeader.find(mesh_id);
-	if (header_it == mMeshHeader.end())
-	{ //we have no header info for this mesh, do nothing
-		mHeaderMutex->unlock();
-		return false;
-	}
-
-	++LLMeshRepository::sMeshRequestCount;
-	U32 header_size = header_it->second.first;
-	bool ret = true;
-
-	if (header_size > 0)
+	if (info.mHeaderSize > 0)
 	{
-		const auto& header = header_it->second.second;
-		S32 version = header["version"].asInteger();
-		S32 offset = header_size + header["physics_mesh"]["offset"].asInteger();
-		S32 size = header["physics_mesh"]["size"].asInteger();
-
-		mHeaderMutex->unlock();
-
-		if (version <= MAX_MESH_VERSION && offset >= 0 && size > 0)
+		if (info.mVersion <= MAX_MESH_VERSION && info.mOffset >= 0 && info.mSize > 0)
 		{
-			//check cache for mesh physics shape info
-			LLFileSystem file(mesh_id, LLAssetType::AT_MESH, LLFileSystem::READ);
-			if (file.open() && file.getSize() >= offset+size)
-			{
-				LLMeshRepository::sCacheBytesRead += size;
-				++LLMeshRepository::sCacheReads;
-				file.seek(offset);
-				U8* buffer = new(std::nothrow) U8[size];
-				if (!buffer)
-				{
-					LL_WARNS_ONCE(LOG_MESH) << "Failed to allocate memory for physics shape, size: " << size << LL_ENDL;
-					return false;
-				}
-				file.read(buffer, size);
-				file.close();
-
-				//make sure buffer isn't all 0's by checking the first 1KB (reserved block but not written)
-				bool zero = true;
-				for (S32 i = 0; i < llmin(size, 1024) && zero; ++i)
-				{
-					zero = buffer[i] > 0 ? false : true;
-				}
-
-				if (!zero)
-				{ //attempt to parse
-					if (physicsShapeReceived(mesh_id, buffer, size) == MESH_OK)
-					{
-						delete[] buffer;
-						return true;
-					}
-				}
-
-				delete[] buffer;
-			}
+			if (loadInfoFromFilesystem(mesh_id, info, boost::bind(&LLMeshRepoThread::physicsShapeReceived, this, _1, _2, _3)))
+				return true;
 
 			//reading from cache failed for whatever reason, fetch from sim
 			std::string http_url;
@@ -1616,15 +1509,15 @@ bool LLMeshRepoThread::fetchMeshPhysicsShape(const LLUUID& mesh_id)
 			
 			if (!http_url.empty())
 			{
-                auto handler = std::make_shared<LLMeshPhysicsShapeHandler>(mesh_id, offset, size);
-				LLCore::HttpHandle handle = getByteRange(http_url, legacy_cap_version, offset, size, handler);
+                auto handler = std::make_shared<LLMeshPhysicsShapeHandler>(mesh_id, info.mOffset, info.mSize);
+				LLCore::HttpHandle handle = getByteRange(http_url, legacy_cap_version, info.mOffset, info.mSize, handler);
 				if (LLCORE_HTTP_HANDLE_INVALID == handle)
 				{
 					LL_WARNS(LOG_MESH) << "HTTP GET request failed for physics shape on mesh " << mID
 									   << ".  Reason:  " << mHttpStatus.toString()
 									   << " (" << mHttpStatus.toTerseString() << ")"
 									   << LL_ENDL;
-					ret = false;
+					return false;
 				}
 				else
 				{
@@ -1638,13 +1531,9 @@ bool LLMeshRepoThread::fetchMeshPhysicsShape(const LLUUID& mesh_id)
 			physicsShapeReceived(mesh_id, NULL, 0);
 		}
 	}
-	else
-	{	
-		mHeaderMutex->unlock();
-	}
 
 	//early out was not hit, effectively fetched
-	return ret;
+	return true;
 }
 
 //static
@@ -1697,6 +1586,11 @@ bool LLMeshRepoThread::fetchMeshHeader(const LLVolumeParams& mesh_params, bool c
 			file.close();
 			if (headerReceived(mesh_params, buffer, bytes) == MESH_OK)
 			{
+#ifdef SHOW_DEBUG
+				std::string mid;
+				mesh_params.getSculptID().toString(mid);
+				LL_DEBUGS(LOG_MESH) << "Mesh/Cache: Mesh header for ID " << mid << " - was retrieved from the cache." << LL_ENDL;
+#endif
 				// Found mesh in cache
 				return true;
 			}
@@ -1711,6 +1605,12 @@ bool LLMeshRepoThread::fetchMeshHeader(const LLVolumeParams& mesh_params, bool c
 	
 	if (!http_url.empty())
 	{
+#ifdef SHOW_DEBUG
+		std::string mid;
+		mesh_params.getSculptID().toString(mid);
+		LL_DEBUGS(LOG_MESH) << "Mesh/Cache: Mesh header for ID " << mid << " - was retrieved from the simulator." << LL_ENDL;
+#endif
+
 		//grab first 4KB if we're going to bother with a fetch.  Cache will prevent future fetches if a full mesh fits
 		//within the first 4KB
 		//NOTE -- this will break of headers ever exceed 4KB		
@@ -1738,71 +1638,20 @@ bool LLMeshRepoThread::fetchMeshHeader(const LLVolumeParams& mesh_params, bool c
 //return false if failed to get mesh lod.
 bool LLMeshRepoThread::fetchMeshLOD(const LLVolumeParams& mesh_params, S32 lod, bool can_retry)
 {
-	if (!mHeaderMutex)
-	{
-		return false;
-	}
-
-	const LLUUID& mesh_id = mesh_params.getSculptID();
+	LLUUID mesh_id = mesh_params.getSculptID();
+	MeshHeaderInfo info;
 
-	mHeaderMutex->lock();
-	auto header_it = mMeshHeader.find(mesh_id);
-	if (header_it == mMeshHeader.end())
-	{ //we have no header info for this mesh, do nothing
-		mHeaderMutex->unlock();
+	if (!getMeshHeaderInfo(mesh_id, header_lod[lod].c_str(), info))
+	{
 		return false;
 	}
-	++LLMeshRepository::sMeshRequestCount;
-	bool retval = true;
-	
-	U32 header_size = header_it->second.first;
-	if (header_size > 0)
+			
+	if (info.mHeaderSize > 0)
 	{
-		const auto& header = header_it->second.second;
-		S32 version = header["version"].asInteger();
-		S32 offset = header_size + header[header_lod[lod]]["offset"].asInteger();
-		S32 size = header[header_lod[lod]]["size"].asInteger();
-		mHeaderMutex->unlock();
-				
-		if (version <= MAX_MESH_VERSION && offset >= 0 && size > 0)
+		if(info.mVersion <= MAX_MESH_VERSION && info.mOffset >= 0 && info.mSize > 0)
 		{
-
-			//check cache for mesh asset
-			LLFileSystem file(mesh_id, LLAssetType::AT_MESH, LLFileSystem::READ);
-			if (file.open() && file.getSize() >= offset+size)
-			{
-				U8* buffer = new(std::nothrow) U8[size];
-				if (!buffer)
-				{
-					LL_WARNS_ONCE(LOG_MESH) << "Can't allocate memory for mesh " << mesh_id << " LOD " << lod << ", size: " << size << LL_ENDL;
-					// todo: for now it will result in indefinite constant retries, should result in timeout
-					// or in retry-count and disabling mesh. (but usually viewer is beyond saving at this point)
-					return false;
-				}
-				LLMeshRepository::sCacheBytesRead += size;
-				++LLMeshRepository::sCacheReads;
-				file.seek(offset);
-				file.read(buffer, size);
-				file.close();
-
-				//make sure buffer isn't all 0's by checking the first 1KB (reserved block but not written)
-				bool zero = true;
-				for (S32 i = 0; i < llmin(size, 1024) && zero; ++i)
-				{
-					zero = buffer[i] > 0 ? false : true;
-				}
-
-				if (!zero)
-				{ //attempt to parse
-					if (lodReceived(mesh_params, lod, buffer, size) == MESH_OK)
-					{
-						delete[] buffer;
-						return true;
-					}
-				}
-
-				delete[] buffer;
-			}
+			if (loadInfoFromFilesystem(mesh_id, info, boost::bind(&LLMeshRepoThread::lodReceived, this, mesh_params, lod, _2, _3 )))
+				return true;
 
 			//reading from cache failed for whatever reason, fetch from sim
 			std::string http_url;
@@ -1811,15 +1660,20 @@ bool LLMeshRepoThread::fetchMeshLOD(const LLVolumeParams& mesh_params, S32 lod,
 			
 			if (!http_url.empty())
 			{
-                auto handler = std::make_shared<LLMeshLODHandler>(mesh_params, lod, offset, size);
-				LLCore::HttpHandle handle = getByteRange(http_url, legacy_cap_version, offset, size, handler);
+#if SHOW_DEBUG			
+				std::string mid;
+				mesh_id.toString(mid);
+				LL_DEBUGS(LOG_MESH) << "Mesh/Cache: Mesh body for ID " << mid << " - was retrieved from the simulator." << LL_ENDL;
+#endif
+                auto handler = std::make_shared<LLMeshLODHandler>(mesh_params, lod, info.mOffset, info.mSize);
+				LLCore::HttpHandle handle = getByteRange(http_url, legacy_cap_version, info.mOffset, info.mSize, handler);
 				if (LLCORE_HTTP_HANDLE_INVALID == handle)
 				{
 					LL_WARNS(LOG_MESH) << "HTTP GET request failed for LOD on mesh " << mID
 									   << ".  Reason:  " << mHttpStatus.toString()
 									   << " (" << mHttpStatus.toTerseString() << ")"
 									   << LL_ENDL;
-					retval = false;
+					return false;
 				}
 				else if (can_retry)
 				{
@@ -1850,7 +1704,7 @@ bool LLMeshRepoThread::fetchMeshLOD(const LLVolumeParams& mesh_params, S32 lod,
 		mHeaderMutex->unlock();
 	}
 
-	return retval;
+	return true;
 }
 
 EMeshProcessingResult LLMeshRepoThread::headerReceived(const LLVolumeParams& mesh_params, U8* data, S32 data_size)
@@ -1907,7 +1761,6 @@ EMeshProcessingResult LLMeshRepoThread::headerReceived(const LLVolumeParams& mes
             LLMeshRepository::sCacheBytesHeaders += header_size;
 		}
 
-		
 		LLMutexLock lock(mMutex); // make sure only one thread access mPendingLOD at the same time.
 
 		//check for pending requests
@@ -1935,7 +1788,6 @@ EMeshProcessingResult LLMeshRepoThread::lodReceived(const LLVolumeParams& mesh_p
 	}
 
 	LLPointer<LLVolume> volume = new LLVolume(mesh_params, LLVolumeLODGroup::getVolumeScaleFromDetail(lod));
-
 	if (volume->unpackVolumeFaces(data, data_size))
 	{
 		if (volume->getNumFaces() > 0)
@@ -2887,7 +2739,7 @@ void LLMeshRepoThread::notifyLoadedMeshes()
 			// Process the elements free of the lock
 			for (const auto& mesh : loaded_queue)
 			{
-				if (mesh.mVolume->getNumVolumeFaces() > 0)
+				if (mesh.mVolume && mesh.mVolume->getNumVolumeFaces() > 0)
 				{
 					gMeshRepo.notifyMeshLoaded(mesh.mMeshParams, mesh.mVolume);
 				}
@@ -3640,13 +3492,13 @@ void LLMeshRepository::unregisterMesh(LLVOVolume* vobj)
 	{
 		for (auto& param : lod)
 		{
-			vector_replace_with_last(param.second, vobj);
+			param.second.erase(vobj);
 		}
 	}
 
 	for (auto& skin_pair : mLoadingSkins)
 	{
-		vector_replace_with_last(skin_pair.second, vobj);
+		skin_pair.second.erase(vobj);
 	}
 }
 
@@ -3665,18 +3517,20 @@ S32 LLMeshRepository::loadMesh(LLVOVolume* vobj, const LLVolumeParams& mesh_para
 	{
 		LLMutexLock lock(mMeshMutex);
 		//add volume to list of loading meshes
-		mesh_load_map::iterator iter = mLoadingMeshes[detail].find(mesh_params.getSculptID());
+		const auto& mesh_id = mesh_params.getSculptID();
+		mesh_load_map::iterator iter = mLoadingMeshes[detail].find(mesh_id);
 		if (iter != mLoadingMeshes[detail].end())
 		{ //request pending for this mesh, append volume id to list
-			auto it = std::find(iter->second.begin(), iter->second.end(), vobj);
-			if (it == iter->second.end()) {
-				iter->second.push_back(vobj);
+			auto& obj_set = iter->second;
+			auto it = obj_set.find(vobj);
+			if (it == obj_set.end()) {
+				obj_set.insert(vobj);
 			}
 		}
 		else
 		{
 			//first request for this mesh
-			mLoadingMeshes[detail][mesh_params.getSculptID()].push_back(vobj);
+			mLoadingMeshes[detail][mesh_id].insert(vobj);
 			mPendingRequests.emplace_back(mesh_params, detail);
 			LLMeshRepository::sLODPending++;
 		}
@@ -4011,7 +3865,7 @@ void LLMeshRepository::notifyLoadedMeshes()
 
 void LLMeshRepository::notifySkinInfoReceived(LLMeshSkinInfo* info)
 {
-	auto pair = mSkinMap.emplace(info->mMeshID, info); // Cache into LLPointer
+	mSkinMap[info->mMeshID] = info; // Cache into LLPointer
     // Alternative: We can get skin size from header
     sCacheBytesSkins += info->sizeBytes();
 
@@ -4022,7 +3876,7 @@ void LLMeshRepository::notifySkinInfoReceived(LLMeshSkinInfo* info)
 		{
 			if (vobj)
 			{
-				vobj->notifySkinInfoLoaded(((*pair.first).second));
+				vobj->notifySkinInfoLoaded(info);
 			}
 		}
 		mLoadingSkins.erase(iter);
@@ -4148,32 +4002,33 @@ LLPointer<LLMeshSkinInfo> LLMeshRepository::getSkinInfo(const LLUUID& mesh_id, L
     if (mesh_id.notNull())
     {
         skin_map::iterator iter = mSkinMap.find(mesh_id);
-		if (iter != mSkinMap.end())
-		{
-			return iter->second;
-		}
-		
-		//no skin info known about given mesh, try to fetch it
-		{
-			LLMutexLock lock(mMeshMutex);
-			//add volume to list of loading meshes
-			skin_load_map::iterator iter = mLoadingSkins.find(mesh_id);
+        if (iter != mSkinMap.end())
+        {
+            return iter->second;
+        }
+
+        //no skin info known about given mesh, try to fetch it
+        if (requesting_obj != nullptr)
+        {
+            LLMutexLock lock(mMeshMutex);
+            //add volume to list of loading meshes
+            skin_load_map::iterator iter = mLoadingSkins.find(mesh_id);
 			if (iter != mLoadingSkins.end())
 			{ //request pending for this mesh, append volume id to list
-				auto it = std::find(iter->second.begin(), iter->second.end(), requesting_obj);
-				if (it == iter->second.end()) {
-					iter->second.push_back(requesting_obj);
+				auto& obj_set = iter->second;
+				auto it = obj_set.find(requesting_obj);
+				if (it == obj_set.end()) {
+					obj_set.insert(requesting_obj);
 				}
 			}
 			else
 			{
 				//first request for this mesh
-				mLoadingSkins[mesh_id].push_back(requesting_obj);
-				mPendingSkinRequests.push(mesh_id);
-			}
-		}
-	}
-
+				mLoadingSkins[mesh_id].insert(requesting_obj);
+                mPendingSkinRequests.push(mesh_id);
+            }
+        }
+    }
 	return nullptr;
 }
 
diff --git a/indra/newview/llmeshrepository.h b/indra/newview/llmeshrepository.h
index f48797b9190..64896942e84 100644
--- a/indra/newview/llmeshrepository.h
+++ b/indra/newview/llmeshrepository.h
@@ -283,6 +283,16 @@ class LLMeshRepoThread final : public LLThread
 
 	};
 
+	struct MeshHeaderInfo
+	{
+		MeshHeaderInfo()
+			: mHeaderSize(0), mVersion(0), mOffset(-1), mSize(0) {}
+		U32 mHeaderSize;
+		U32 mVersion;
+		S32 mOffset;
+		S32 mSize;
+	};
+
 	/////////
 	// In flight queues
 	/////////
@@ -363,6 +373,9 @@ class LLMeshRepoThread final : public LLThread
 	EMeshProcessingResult physicsShapeReceived(const LLUUID& mesh_id, U8* data, S32 data_size);
 	bool hasPhysicsShapeInHeader(const LLUUID& mesh_id);
 
+	bool getMeshHeaderInfo(const LLUUID& mesh_id, const char* block_name, MeshHeaderInfo& info);
+	bool loadInfoFromFilesystem(const LLUUID& mesh_id, MeshHeaderInfo& info, boost::function<bool(const LLUUID&, U8*, S32)> fn);
+
 	void notifyLoadedMeshes(); // Only call from main thread.
 	S32 getActualMeshLOD(const LLVolumeParams& mesh_params, S32 lod);
 	
@@ -633,7 +646,7 @@ class LLMeshRepository
 	static void metricsProgress(unsigned int count);
 	static void metricsUpdate();
 	
-	typedef boost::unordered_map<LLUUID, std::vector<LLVOVolume*> > mesh_load_map;
+	typedef boost::unordered_map<LLUUID, boost::unordered_set<LLVOVolume*> > mesh_load_map;
 	mesh_load_map mLoadingMeshes[4];
 	
 	typedef boost::unordered_flat_map<LLUUID, LLPointer<LLMeshSkinInfo>> skin_map;
@@ -647,7 +660,7 @@ class LLMeshRepository
 	std::vector<LLMeshRepoThread::LODRequest> mPendingRequests;
 	
 	//list of mesh ids awaiting skin info
-	typedef boost::unordered_map<LLUUID, std::vector<LLVOVolume*> > skin_load_map;
+	typedef boost::unordered_map<LLUUID, boost::unordered_set<LLVOVolume*> > skin_load_map;
 	skin_load_map mLoadingSkins;
 
 	//list of mesh ids that need to send skin info fetch requests
diff --git a/indra/newview/llspatialpartition.h b/indra/newview/llspatialpartition.h
index a5db551dd84..6c50893d7ea 100644
--- a/indra/newview/llspatialpartition.h
+++ b/indra/newview/llspatialpartition.h
@@ -118,7 +118,7 @@ class LLDrawInfo : public LLRefCount
 	U8   mDiffuseAlphaMode;
 	bool mSelected;
     LLPointer<LLVOAvatar> mAvatar = nullptr;
-    LLMeshSkinInfo* mSkinInfo = nullptr;
+    LLPointer<LLMeshSkinInfo> mSkinInfo = nullptr;
 
 
 	struct CompareTexture
diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp
index 926c787e841..6cc435420a5 100644
--- a/indra/newview/llvovolume.cpp
+++ b/indra/newview/llvovolume.cpp
@@ -234,10 +234,7 @@ LLVOVolume::LLVOVolume(const LLUUID &id, const LLPCode pcode, LLViewerRegion *re
     mColorChanged = FALSE;
 	mSpotLightPriority = 0.f;
 
-	mSkinInfoFailed = false;
 	mSkinInfo = NULL;
-	mSkinRenderMatrixJointCount = 0;
-	mSkinLastRenderFrame = 0;
 
 	mMediaImplList.resize(getNumTEs());
 	mLastFetchedMediaVersion = -1;
@@ -257,7 +254,10 @@ LLVOVolume::~LLVOVolume()
 
 	mSkinInfo = nullptr;
 
-	gMeshRepo.unregisterMesh(this);
+	//if(mMeshDataInFlight || mSkinInfoInFlight)
+	{
+		gMeshRepo.unregisterMesh(this);
+	}
 
 	if(!mMediaImplList.empty())
 	{
@@ -1117,7 +1117,6 @@ BOOL LLVOVolume::setVolume(const LLVolumeParams &params_in, const S32 detail, bo
 				if (mSkinInfo && mSkinInfo->mMeshID != volume_params.getSculptID())
 				{
 					mSkinInfo = NULL;
-					mSkinInfoFailed = false;
 				}
 
 				if (!getVolume()->isMeshAssetLoaded())
@@ -1130,12 +1129,12 @@ BOOL LLVOVolume::setVolume(const LLVolumeParams &params_in, const S32 detail, bo
 					}
 				}
 				
-				if (!mSkinInfo && !hasSkinInfoFailed())
+				if (!mSkinInfo)
 				{
-					mSkinInfo = gMeshRepo.getSkinInfo(volume_params.getSculptID(), this);
-					if (mSkinInfo)
+					const LLMeshSkinInfo* skin_info = gMeshRepo.getSkinInfo(volume_params.getSculptID(), this);
+					if (skin_info)
 					{
-						notifySkinInfoLoaded(mSkinInfo);
+						notifySkinInfoLoaded(skin_info);
 					}
 				}
 			}
@@ -1171,7 +1170,6 @@ void LLVOVolume::updateSculptTexture()
 			mSculptTexture = LLViewerTextureManager::getFetchedTexture(id, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE);
 		}
 
-		mSkinInfoFailed = false;
 		mSkinInfo = NULL;
 	}
 	else
@@ -1227,17 +1225,29 @@ void LLVOVolume::notifyMeshLoaded()
     updateVisualComplexity();
 }
 
-void LLVOVolume::notifySkinInfoLoaded(LLMeshSkinInfo* skin)
+void LLVOVolume::notifySkinInfoLoaded(const LLMeshSkinInfo* skin)
 {
-	mSkinInfoFailed = false;
 	mSkinInfo = skin;
+	mSculptChanged = TRUE;
+	gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_GEOMETRY, TRUE);
 
-	notifyMeshLoaded();
+    LLVOAvatar *av = getAvatar();
+    if (av && !isAnimatedObject())
+    {
+        av->addAttachmentOverridesForObject(this);
+        av->notifyAttachmentMeshLoaded();
+    }
+    LLControlAvatar *cav = getControlAvatar();
+    if (cav && isAnimatedObject())
+    {
+        cav->addAttachmentOverridesForObject(this);
+        cav->notifyAttachmentMeshLoaded();
+    }
+    updateVisualComplexity();
 }
 
 void LLVOVolume::notifySkinInfoUnavailable()
 {
-	mSkinInfoFailed = true;
 	mSkinInfo = nullptr;
 }
 
diff --git a/indra/newview/llvovolume.h b/indra/newview/llvovolume.h
index 764d398df53..30c9e4d4bc6 100644
--- a/indra/newview/llvovolume.h
+++ b/indra/newview/llvovolume.h
@@ -357,7 +357,7 @@ class LLVOVolume final : public LLViewerObject
     void updateVisualComplexity();
     
 	void notifyMeshLoaded();
-	void notifySkinInfoLoaded(LLMeshSkinInfo* skin);
+	void notifySkinInfoLoaded(const LLMeshSkinInfo* skin);
 	void notifySkinInfoUnavailable();
 	
 	// Returns 'true' iff the media data for this object is in flight
@@ -442,15 +442,7 @@ class LLVOVolume final : public LLViewerObject
 	bool mResetDebugText;
 
 	LLPointer<LLRiggedVolume> mRiggedVolume;
-
-	bool hasSkinInfoFailed() const { return mSkinInfoFailed; }
-
-	bool mSkinInfoFailed;
-	LLPointer<LLMeshSkinInfo> mSkinInfo;
-	std::unique_ptr <LLMatrix4a[]> mSkinMatrixCache;
-	std::unique_ptr <F32[]> mSkinRenderMatrixCache;
-	U32 mSkinRenderMatrixJointCount;
-	U32 mSkinLastRenderFrame;
+	LLConstPointer<LLMeshSkinInfo> mSkinInfo;
 	
 	// statics
 public:
-- 
GitLab