summaryrefslogtreecommitdiff
path: root/indra/newview/llmeshrepository.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'indra/newview/llmeshrepository.cpp')
-rw-r--r--indra/newview/llmeshrepository.cpp500
1 files changed, 326 insertions, 174 deletions
diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp
index fdaa28b22b..bb14a29ca3 100644
--- a/indra/newview/llmeshrepository.cpp
+++ b/indra/newview/llmeshrepository.cpp
@@ -353,6 +353,9 @@ const U32 LARGE_MESH_FETCH_THRESHOLD = 1U << 21; // Size at which requests goes
const long SMALL_MESH_XFER_TIMEOUT = 120L; // Seconds to complete xfer, small mesh downloads
const long LARGE_MESH_XFER_TIMEOUT = 600L; // Seconds to complete xfer, large downloads
+const U32 DOWNLOAD_RETRY_LIMIT = 8;
+const F32 DOWNLOAD_RETRY_DELAY = 0.5f; // seconds
+
// Would normally like to retry on uploads as some
// retryable failures would be recoverable. Unfortunately,
// the mesh service is using 500 (retryable) rather than
@@ -516,6 +519,24 @@ void get_vertex_buffer_from_mesh(LLCDMeshData& mesh, LLModel::PhysicsMesh& res,
}
}
+void RequestStats::updateTime()
+{
+ U32 modifier = 1 << mRetries; // before ++
+ mRetries++;
+ mTimer.reset();
+ mTimer.setTimerExpirySec(DOWNLOAD_RETRY_DELAY * (F32)modifier); // up to 32s, 64 total wait
+}
+
+bool RequestStats::canRetry() const
+{
+ return mRetries < DOWNLOAD_RETRY_LIMIT;
+}
+
+bool RequestStats::isDelayed() const
+{
+ return mTimer.getStarted() && !mTimer.hasExpired();
+}
+
LLViewerFetchedTexture* LLMeshUploadThread::FindViewerTexture(const LLImportMaterial& material)
{
LLPointer< LLViewerFetchedTexture > * ppTex = static_cast< LLPointer< LLViewerFetchedTexture > * >(material.mOpaqueData);
@@ -836,6 +857,12 @@ LLMeshRepoThread::~LLMeshRepoThread()
mHttpRequestSet.clear();
mHttpHeaders.reset();
+ while (!mDecompositionQ.empty())
+ {
+ delete mDecompositionQ.front();
+ mDecompositionQ.pop_front();
+ }
+
delete mHttpRequest;
mHttpRequest = NULL;
delete mMutex;
@@ -884,141 +911,225 @@ void LLMeshRepoThread::run()
sRequestWaterLevel = mHttpRequestSet.size(); // Stats data update
// NOTE: order of queue processing intentionally favors LOD requests over header requests
+ // Todo: we are processing mLODReqQ, mHeaderReqQ, mSkinRequests, mDecompositionRequests and mPhysicsShapeRequests
+ // in relatively similar manners, remake code to simplify/unify the process,
+ // like processRequests(&requestQ, fetchFunction); which does same thing for each element
- while (!mLODReqQ.empty() && mHttpRequestSet.size() < sRequestHighWater)
- {
- if (! mMutex)
- {
- break;
- }
- mMutex->lock();
- LODRequest req = mLODReqQ.front();
- mLODReqQ.pop();
- LLMeshRepository::sLODProcessing--;
- mMutex->unlock();
-
- if (!fetchMeshLOD(req.mMeshParams, req.mLOD)) // failed, resubmit
- {
- mMutex->lock();
- mLODReqQ.push(req);
- ++LLMeshRepository::sLODProcessing;
- mMutex->unlock();
- }
- }
-
- while (!mHeaderReqQ.empty() && mHttpRequestSet.size() < sRequestHighWater)
- {
- if (! mMutex)
- {
- break;
- }
- mMutex->lock();
- HeaderRequest req = mHeaderReqQ.front();
- mHeaderReqQ.pop();
- mMutex->unlock();
- if (!fetchMeshHeader(req.mMeshParams))//failed, resubmit
- {
- mMutex->lock();
- mHeaderReqQ.push(req) ;
- mMutex->unlock();
- }
- }
-
- // For the final three request lists, similar goal to above but
- // slightly different queue structures. Stay off the mutex when
- // performing long-duration actions.
-
- if (mHttpRequestSet.size() < sRequestHighWater
- && (! mSkinRequests.empty()
- || ! mDecompositionRequests.empty()
- || ! mPhysicsShapeRequests.empty()))
- {
- // Something to do probably, lock and double-check. We don't want
- // to hold the lock long here. That will stall main thread activities
- // so we bounce it.
-
- mMutex->lock();
- if (! mSkinRequests.empty() && mHttpRequestSet.size() < sRequestHighWater)
- {
- std::set<LLUUID> incomplete;
- std::set<LLUUID>::iterator iter(mSkinRequests.begin());
- while (iter != mSkinRequests.end() && mHttpRequestSet.size() < sRequestHighWater)
- {
- LLUUID mesh_id = *iter;
- mSkinRequests.erase(iter);
- mMutex->unlock();
-
- if (! fetchMeshSkinInfo(mesh_id))
- {
- incomplete.insert(mesh_id);
- }
+ if (!mLODReqQ.empty() && mHttpRequestSet.size() < sRequestHighWater)
+ {
+ std::list<LODRequest> incomplete;
+ while (!mLODReqQ.empty() && mHttpRequestSet.size() < sRequestHighWater)
+ {
+ if (!mMutex)
+ {
+ break;
+ }
+
+ mMutex->lock();
+ LODRequest req = mLODReqQ.front();
+ mLODReqQ.pop();
+ LLMeshRepository::sLODProcessing--;
+ mMutex->unlock();
+ if (req.isDelayed())
+ {
+ // failed to load before, wait a bit
+ incomplete.push_front(req);
+ }
+ else if (!fetchMeshLOD(req.mMeshParams, req.mLOD, req.canRetry()))
+ {
+ if (req.canRetry())
+ {
+ // failed, resubmit
+ req.updateTime();
+ incomplete.push_front(req);
+ }
+ else
+ {
+ // too many fails
+ mUnavailableQ.push(req);
+ LL_WARNS() << "Failed to load " << req.mMeshParams << " , skip" << LL_ENDL;
+ }
+ }
+ }
- mMutex->lock();
- iter = mSkinRequests.begin();
- }
+ if (!incomplete.empty())
+ {
+ LLMutexLock locker(mMutex);
+ for (std::list<LODRequest>::iterator iter = incomplete.begin(); iter != incomplete.end(); iter++)
+ {
+ mLODReqQ.push(*iter);
+ ++LLMeshRepository::sLODProcessing;
+ }
+ }
+ }
- if (! incomplete.empty())
- {
- mSkinRequests.insert(incomplete.begin(), incomplete.end());
- }
- }
+ if (!mHeaderReqQ.empty() && mHttpRequestSet.size() < sRequestHighWater)
+ {
+ std::list<HeaderRequest> incomplete;
+ while (!mHeaderReqQ.empty() && mHttpRequestSet.size() < sRequestHighWater)
+ {
+ if (!mMutex)
+ {
+ break;
+ }
+
+ mMutex->lock();
+ HeaderRequest req = mHeaderReqQ.front();
+ mHeaderReqQ.pop();
+ mMutex->unlock();
+ if (req.isDelayed())
+ {
+ // failed to load before, wait a bit
+ incomplete.push_front(req);
+ }
+ else if (!fetchMeshHeader(req.mMeshParams, req.canRetry()))
+ {
+ if (req.canRetry())
+ {
+ //failed, resubmit
+ req.updateTime();
+ incomplete.push_front(req);
+ }
+ else
+ {
+ LL_DEBUGS() << "mHeaderReqQ failed: " << req.mMeshParams << LL_ENDL;
+ }
+ }
+ }
- // holding lock, try next list
- // *TODO: For UI/debug-oriented lists, we might drop the fine-
- // grained locking as there's a lowered expectation of smoothness
- // in these cases.
- if (! mDecompositionRequests.empty() && mHttpRequestSet.size() < sRequestHighWater)
- {
- std::set<LLUUID> incomplete;
- std::set<LLUUID>::iterator iter(mDecompositionRequests.begin());
- while (iter != mDecompositionRequests.end() && mHttpRequestSet.size() < sRequestHighWater)
- {
- LLUUID mesh_id = *iter;
- mDecompositionRequests.erase(iter);
- mMutex->unlock();
-
- if (! fetchMeshDecomposition(mesh_id))
- {
- incomplete.insert(mesh_id);
- }
+ if (!incomplete.empty())
+ {
+ LLMutexLock locker(mMutex);
+ for (std::list<HeaderRequest>::iterator iter = incomplete.begin(); iter != incomplete.end(); iter++)
+ {
+ mHeaderReqQ.push(*iter);
+ }
+ }
+ }
- mMutex->lock();
- iter = mDecompositionRequests.begin();
- }
+ // For the final three request lists, similar goal to above but
+ // slightly different queue structures. Stay off the mutex when
+ // performing long-duration actions.
- if (! incomplete.empty())
- {
- mDecompositionRequests.insert(incomplete.begin(), incomplete.end());
- }
- }
+ if (mHttpRequestSet.size() < sRequestHighWater
+ && (!mSkinRequests.empty()
+ || !mDecompositionRequests.empty()
+ || !mPhysicsShapeRequests.empty()))
+ {
+ // Something to do probably, lock and double-check. We don't want
+ // to hold the lock long here. That will stall main thread activities
+ // so we bounce it.
- // holding lock, final list
- if (! mPhysicsShapeRequests.empty() && mHttpRequestSet.size() < sRequestHighWater)
- {
- std::set<LLUUID> incomplete;
- std::set<LLUUID>::iterator iter(mPhysicsShapeRequests.begin());
- while (iter != mPhysicsShapeRequests.end() && mHttpRequestSet.size() < sRequestHighWater)
- {
- LLUUID mesh_id = *iter;
- mPhysicsShapeRequests.erase(iter);
- mMutex->unlock();
-
- if (! fetchMeshPhysicsShape(mesh_id))
- {
- incomplete.insert(mesh_id);
- }
+ if (!mSkinRequests.empty())
+ {
+ std::set<UUIDBasedRequest> incomplete;
+ while (!mSkinRequests.empty() && mHttpRequestSet.size() < sRequestHighWater)
+ {
+ mMutex->lock();
+ std::set<UUIDBasedRequest>::iterator iter = mSkinRequests.begin();
+ UUIDBasedRequest req = *iter;
+ mSkinRequests.erase(iter);
+ mMutex->unlock();
+ if (req.isDelayed())
+ {
+ incomplete.insert(req);
+ }
+ else if (!fetchMeshSkinInfo(req.mId))
+ {
+ if (req.canRetry())
+ {
+ req.updateTime();
+ incomplete.insert(req);
+ }
+ else
+ {
+ LL_DEBUGS() << "mSkinRequests failed: " << req.mId << LL_ENDL;
+ }
+ }
+ }
+
+ if (!incomplete.empty())
+ {
+ LLMutexLock locker(mMutex);
+ mSkinRequests.insert(incomplete.begin(), incomplete.end());
+ }
+ }
- mMutex->lock();
- iter = mPhysicsShapeRequests.begin();
- }
+ // holding lock, try next list
+ // *TODO: For UI/debug-oriented lists, we might drop the fine-
+ // grained locking as there's a lowered expectation of smoothness
+ // in these cases.
+ if (!mDecompositionRequests.empty())
+ {
+ std::set<UUIDBasedRequest> incomplete;
+ while (!mDecompositionRequests.empty() && mHttpRequestSet.size() < sRequestHighWater)
+ {
+ mMutex->lock();
+ std::set<UUIDBasedRequest>::iterator iter = mDecompositionRequests.begin();
+ UUIDBasedRequest req = *iter;
+ mDecompositionRequests.erase(iter);
+ mMutex->unlock();
+ if (req.isDelayed())
+ {
+ incomplete.insert(req);
+ }
+ else if (!fetchMeshDecomposition(req.mId))
+ {
+ if (req.canRetry())
+ {
+ req.updateTime();
+ incomplete.insert(req);
+ }
+ else
+ {
+ LL_DEBUGS() << "mDecompositionRequests failed: " << req.mId << LL_ENDL;
+ }
+ }
+ }
+
+ if (!incomplete.empty())
+ {
+ LLMutexLock locker(mMutex);
+ mDecompositionRequests.insert(incomplete.begin(), incomplete.end());
+ }
+ }
- if (! incomplete.empty())
- {
- mPhysicsShapeRequests.insert(incomplete.begin(), incomplete.end());
- }
- }
- mMutex->unlock();
- }
+ // holding lock, final list
+ if (!mPhysicsShapeRequests.empty())
+ {
+ std::set<UUIDBasedRequest> incomplete;
+ while (!mPhysicsShapeRequests.empty() && mHttpRequestSet.size() < sRequestHighWater)
+ {
+ mMutex->lock();
+ std::set<UUIDBasedRequest>::iterator iter = mPhysicsShapeRequests.begin();
+ UUIDBasedRequest req = *iter;
+ mPhysicsShapeRequests.erase(iter);
+ mMutex->unlock();
+ if (req.isDelayed())
+ {
+ incomplete.insert(req);
+ }
+ else if (!fetchMeshPhysicsShape(req.mId))
+ {
+ if (req.canRetry())
+ {
+ req.updateTime();
+ incomplete.insert(req);
+ }
+ else
+ {
+ LL_DEBUGS() << "mPhysicsShapeRequests failed: " << req.mId << LL_ENDL;
+ }
+ }
+ }
+
+ if (!incomplete.empty())
+ {
+ LLMutexLock locker(mMutex);
+ mPhysicsShapeRequests.insert(incomplete.begin(), incomplete.end());
+ }
+ }
+ }
// For dev purposes only. A dynamic change could make this false
// and that shouldn't assert.
@@ -1040,19 +1151,19 @@ void LLMeshRepoThread::run()
// Mutex: LLMeshRepoThread::mMutex must be held on entry
void LLMeshRepoThread::loadMeshSkinInfo(const LLUUID& mesh_id)
{
- mSkinRequests.insert(mesh_id);
+ mSkinRequests.insert(UUIDBasedRequest(mesh_id));
}
// Mutex: LLMeshRepoThread::mMutex must be held on entry
void LLMeshRepoThread::loadMeshDecomposition(const LLUUID& mesh_id)
{
- mDecompositionRequests.insert(mesh_id);
+ mDecompositionRequests.insert(UUIDBasedRequest(mesh_id));
}
// Mutex: LLMeshRepoThread::mMutex must be held on entry
void LLMeshRepoThread::loadMeshPhysicsShape(const LLUUID& mesh_id)
{
- mPhysicsShapeRequests.insert(mesh_id);
+ mPhysicsShapeRequests.insert(UUIDBasedRequest(mesh_id));
}
void LLMeshRepoThread::lockAndLoadMeshLOD(const LLVolumeParams& mesh_params, S32 lod)
@@ -1112,19 +1223,27 @@ void LLMeshRepoThread::constructUrl(LLUUID mesh_id, std::string * url)
if (gAgent.getRegion())
{
- LLMutexLock lock(mMutex);
- res_url = mGetMeshCapability;
- }
+ {
+ LLMutexLock lock(mMutex);
+ res_url = mGetMeshCapability;
+ }
- if (! res_url.empty())
- {
- res_url += "/?mesh_id=";
- res_url += mesh_id.asString().c_str();
+ if (!res_url.empty())
+ {
+ res_url += "/?mesh_id=";
+ res_url += mesh_id.asString().c_str();
+ }
+ else
+ {
+ LL_WARNS_ONCE(LOG_MESH) << "Current region does not have ViewerAsset capability! Cannot load meshes. Region id: "
+ << gAgent.getRegion()->getRegionID() << LL_ENDL;
+ LL_DEBUGS_ONCE(LOG_MESH) << "Cannot load mesh " << mesh_id << " due to missing capability." << LL_ENDL;
+ }
}
else
{
- LL_WARNS_ONCE(LOG_MESH) << "Current region does not have ViewerAsset capability! Cannot load "
- << mesh_id << ".mesh" << LL_ENDL;
+ LL_WARNS_ONCE(LOG_MESH) << "Current region is not loaded so there is no capability to load from! Cannot load meshes." << LL_ENDL;
+ LL_DEBUGS_ONCE(LOG_MESH) << "Cannot load mesh " << mesh_id << " due to missing capability." << LL_ENDL;
}
*url = res_url;
@@ -1220,16 +1339,16 @@ bool LLMeshRepoThread::fetchMeshSkinInfo(const LLUUID& mesh_id)
//check VFS for mesh skin info
LLVFile file(gVFS, mesh_id, LLAssetType::AT_MESH);
if (file.getSize() >= offset+size)
- {
- LLMeshRepository::sCacheBytesRead += size;
- ++LLMeshRepository::sCacheReads;
- file.seek(offset);
+ {
U8* buffer = new(std::nothrow) U8[size];
if (!buffer)
{
- LL_WARNS(LOG_MESH) << "Failed to allocate memory for skin info" << LL_ENDL;
+ 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);
//make sure buffer isn't all 0's by checking the first 1KB (reserved block but not written)
@@ -1317,16 +1436,16 @@ bool LLMeshRepoThread::fetchMeshDecomposition(const LLUUID& mesh_id)
LLVFile file(gVFS, mesh_id, LLAssetType::AT_MESH);
if (file.getSize() >= offset+size)
{
- LLMeshRepository::sCacheBytesRead += size;
- ++LLMeshRepository::sCacheReads;
-
- file.seek(offset);
U8* buffer = new(std::nothrow) U8[size];
if (!buffer)
{
- LL_WARNS(LOG_MESH) << "Failed to allocate memory for mesh decomposition" << LL_ENDL;
+ 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);
//make sure buffer isn't all 0's by checking the first 1KB (reserved block but not written)
@@ -1420,7 +1539,7 @@ bool LLMeshRepoThread::fetchMeshPhysicsShape(const LLUUID& mesh_id)
U8* buffer = new(std::nothrow) U8[size];
if (!buffer)
{
- LL_WARNS(LOG_MESH) << "Failed to allocate memory for physics shape" << LL_ENDL;
+ LL_WARNS_ONCE(LOG_MESH) << "Failed to allocate memory for physics shape, size: " << size << LL_ENDL;
return false;
}
file.read(buffer, size);
@@ -1510,7 +1629,7 @@ void LLMeshRepoThread::decActiveHeaderRequests()
}
//return false if failed to get header
-bool LLMeshRepoThread::fetchMeshHeader(const LLVolumeParams& mesh_params)
+bool LLMeshRepoThread::fetchMeshHeader(const LLVolumeParams& mesh_params, bool can_retry)
{
++LLMeshRepository::sMeshRequestCount;
@@ -1557,7 +1676,7 @@ bool LLMeshRepoThread::fetchMeshHeader(const LLVolumeParams& mesh_params)
<< LL_ENDL;
retval = false;
}
- else
+ else if (can_retry)
{
handler->mHttpHandle = handle;
mHttpRequestSet.insert(handler);
@@ -1568,7 +1687,7 @@ bool LLMeshRepoThread::fetchMeshHeader(const LLVolumeParams& mesh_params)
}
//return false if failed to get mesh lod.
-bool LLMeshRepoThread::fetchMeshLOD(const LLVolumeParams& mesh_params, S32 lod)
+bool LLMeshRepoThread::fetchMeshLOD(const LLVolumeParams& mesh_params, S32 lod, bool can_retry)
{
if (!mHeaderMutex)
{
@@ -1598,15 +1717,17 @@ bool LLMeshRepoThread::fetchMeshLOD(const LLVolumeParams& mesh_params, S32 lod)
LLVFile file(gVFS, mesh_id, LLAssetType::AT_MESH);
if (file.getSize() >= offset+size)
{
- LLMeshRepository::sCacheBytesRead += size;
- ++LLMeshRepository::sCacheReads;
- file.seek(offset);
U8* buffer = new(std::nothrow) U8[size];
if (!buffer)
{
- LL_WARNS(LOG_MESH) << "Can't allocate memory for mesh LOD" << LL_ENDL;
+ 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);
//make sure buffer isn't all 0's by checking the first 1KB (reserved block but not written)
@@ -1618,7 +1739,7 @@ bool LLMeshRepoThread::fetchMeshLOD(const LLVolumeParams& mesh_params, S32 lod)
if (!zero)
{ //attempt to parse
- if (lodReceived(mesh_params, lod, buffer, size))
+ if (lodReceived(mesh_params, lod, buffer, size) == MESH_OK)
{
delete[] buffer;
return true;
@@ -1644,12 +1765,16 @@ bool LLMeshRepoThread::fetchMeshLOD(const LLVolumeParams& mesh_params, S32 lod)
<< LL_ENDL;
retval = false;
}
- else
+ else if (can_retry)
{
handler->mHttpHandle = handle;
mHttpRequestSet.insert(handler);
// *NOTE: Allowing a re-request, not marking as unavailable. Is that correct?
}
+ else
+ {
+ mUnavailableQ.push(LODRequest(mesh_params, lod));
+ }
}
else
{
@@ -1734,11 +1859,11 @@ bool LLMeshRepoThread::headerReceived(const LLVolumeParams& mesh_params, U8* dat
return true;
}
-bool LLMeshRepoThread::lodReceived(const LLVolumeParams& mesh_params, S32 lod, U8* data, S32 data_size)
+EMeshProcessingResult LLMeshRepoThread::lodReceived(const LLVolumeParams& mesh_params, S32 lod, U8* data, S32 data_size)
{
if (data == NULL || data_size == 0)
{
- return false;
+ return MESH_NO_DATA;
}
LLPointer<LLVolume> volume = new LLVolume(mesh_params, LLVolumeLODGroup::getVolumeScaleFromDetail(lod));
@@ -1751,7 +1876,7 @@ bool LLMeshRepoThread::lodReceived(const LLVolumeParams& mesh_params, S32 lod, U
catch (std::bad_alloc)
{
// out of memory, we won't be able to process this mesh
- return false;
+ return MESH_OUT_OF_MEMORY;
}
if (volume->unpackVolumeFaces(stream, data_size))
@@ -1763,11 +1888,11 @@ bool LLMeshRepoThread::lodReceived(const LLVolumeParams& mesh_params, S32 lod, U
LLMutexLock lock(mMutex);
mLoadedQ.push(mesh);
}
- return true;
+ return MESH_OK;
}
}
- return false;
+ return MESH_UNKNOWN;
}
bool LLMeshRepoThread::skinInfoReceived(const LLUUID& mesh_id, U8* data, S32 data_size)
@@ -1941,6 +2066,9 @@ LLMeshUploadThread::~LLMeshUploadThread()
{
delete mHttpRequest;
mHttpRequest = NULL;
+ delete mMutex;
+ mMutex = NULL;
+
}
LLMeshUploadThread::DecompRequest::DecompRequest(LLModel* mdl, LLModel* base_model, LLMeshUploadThread* thread)
@@ -2952,6 +3080,11 @@ void LLMeshHandlerBase::onCompleted(LLCore::HttpHandle handle, LLCore::HttpRespo
body->read(body_offset, (char *) data, data_size - body_offset);
LLMeshRepository::sBytesReceived += data_size;
}
+ else
+ {
+ LL_WARNS(LOG_MESH) << "Failed to allocate " << data_size - body_offset << " memory for mesh response" << LL_ENDL;
+ processFailure(LLCore::HttpStatus(LLCore::HttpStatus::LLCORE, LLCore::HE_BAD_ALLOC));
+ }
}
processData(body, body_offset, data, data_size - body_offset);
@@ -3127,27 +3260,43 @@ void LLMeshLODHandler::processData(LLCore::BufferArray * /* body */, S32 /* body
U8 * data, S32 data_size)
{
if ((!MESH_LOD_PROCESS_FAILED)
- && ((data != NULL) == (data_size > 0)) // if we have data but no size or have size but no data, something is wrong
- && gMeshRepo.mThread->lodReceived(mMeshParams, mLOD, data, data_size))
+ && ((data != NULL) == (data_size > 0))) // if we have data but no size or have size but no data, something is wrong
{
- // good fetch from sim, write to VFS for caching
- LLVFile file(gVFS, mMeshParams.getSculptID(), LLAssetType::AT_MESH, LLVFile::WRITE);
+ EMeshProcessingResult result = gMeshRepo.mThread->lodReceived(mMeshParams, mLOD, data, data_size);
+ if (result == MESH_OK)
+ {
+ // good fetch from sim, write to VFS for caching
+ LLVFile file(gVFS, mMeshParams.getSculptID(), LLAssetType::AT_MESH, LLVFile::WRITE);
- S32 offset = mOffset;
- S32 size = mRequestedBytes;
+ S32 offset = mOffset;
+ S32 size = mRequestedBytes;
- if (file.getSize() >= offset+size)
+ if (file.getSize() >= offset+size)
+ {
+ file.seek(offset);
+ file.write(data, size);
+ LLMeshRepository::sCacheBytesWritten += size;
+ ++LLMeshRepository::sCacheWrites;
+ }
+ }
+ else
{
- file.seek(offset);
- file.write(data, size);
- LLMeshRepository::sCacheBytesWritten += size;
- ++LLMeshRepository::sCacheWrites;
+ LL_WARNS(LOG_MESH) << "Error during mesh LOD processing. ID: " << mMeshParams.getSculptID()
+ << ", Reason: " << result
+ << " LOD: " << mLOD
+ << " Data size: " << data_size
+ << " Not retrying."
+ << LL_ENDL;
+ LLMutexLock lock(gMeshRepo.mThread->mMutex);
+ gMeshRepo.mThread->mUnavailableQ.push(LLMeshRepoThread::LODRequest(mMeshParams, mLOD));
}
}
else
{
LL_WARNS(LOG_MESH) << "Error during mesh LOD processing. ID: " << mMeshParams.getSculptID()
<< ", Unknown reason. Not retrying."
+ << " LOD: " << mLOD
+ << " Data size: " << data_size
<< LL_ENDL;
LLMutexLock lock(gMeshRepo.mThread->mMutex);
gMeshRepo.mThread->mUnavailableQ.push(LLMeshRepoThread::LODRequest(mMeshParams, mLOD));
@@ -3300,6 +3449,7 @@ void LLMeshPhysicsShapeHandler::processData(LLCore::BufferArray * /* body */, S3
LLMeshRepository::LLMeshRepository()
: mMeshMutex(NULL),
+ mDecompThread(NULL),
mMeshThreadCount(0),
mThread(NULL)
{
@@ -3329,6 +3479,8 @@ void LLMeshRepository::init()
void LLMeshRepository::shutdown()
{
LL_INFOS(LOG_MESH) << "Shutting down mesh repository." << LL_ENDL;
+ llassert(mThread != NULL);
+ llassert(mThread->mSignal != NULL);
metrics_teleport_started_signal.disconnect();