summaryrefslogtreecommitdiff
path: root/indra/newview/llmeshrepository.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'indra/newview/llmeshrepository.cpp')
-rwxr-xr-xindra/newview/llmeshrepository.cpp524
1 files changed, 284 insertions, 240 deletions
diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp
index 8f50555a73..648056484e 100755
--- a/indra/newview/llmeshrepository.cpp
+++ b/indra/newview/llmeshrepository.cpp
@@ -1,4 +1,3 @@
-
/**
* @file llmeshrepository.cpp
* @brief Mesh repository implementation.
@@ -72,6 +71,7 @@
#include "bufferarray.h"
#include "bufferstream.h"
#include "llfasttimer.h"
+#include "llcorehttputil.h"
#include "boost/lexical_cast.hpp"
@@ -338,14 +338,17 @@ static LLFastTimer::DeclareTimer FTM_MESH_FETCH("Mesh Fetch");
LLMeshRepository gMeshRepo;
const S32 MESH_HEADER_SIZE = 4096; // Important: assumption is that headers fit in this space
+
const S32 REQUEST_HIGH_WATER_MIN = 32; // Limits for GetMesh regions
const S32 REQUEST_HIGH_WATER_MAX = 150; // Should remain under 2X throttle
const S32 REQUEST_LOW_WATER_MIN = 16;
const S32 REQUEST_LOW_WATER_MAX = 75;
+
const S32 REQUEST2_HIGH_WATER_MIN = 32; // Limits for GetMesh2 regions
-const S32 REQUEST2_HIGH_WATER_MAX = 80;
+const S32 REQUEST2_HIGH_WATER_MAX = 100;
const S32 REQUEST2_LOW_WATER_MIN = 16;
-const S32 REQUEST2_LOW_WATER_MAX = 40;
+const S32 REQUEST2_LOW_WATER_MAX = 50;
+
const U32 LARGE_MESH_FETCH_THRESHOLD = 1U << 21; // Size at which requests goes to narrow/slow queue
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
@@ -518,11 +521,13 @@ class LLMeshHandlerBase : public LLCore::HttpHandler
{
public:
LOG_CLASS(LLMeshHandlerBase);
- LLMeshHandlerBase()
+ LLMeshHandlerBase(U32 offset, U32 requested_bytes)
: LLCore::HttpHandler(),
mMeshParams(),
mProcessed(false),
- mHttpHandle(LLCORE_HTTP_HANDLE_INVALID)
+ mHttpHandle(LLCORE_HTTP_HANDLE_INVALID),
+ mOffset(offset),
+ mRequestedBytes(requested_bytes)
{}
virtual ~LLMeshHandlerBase()
@@ -534,13 +539,15 @@ protected:
public:
virtual void onCompleted(LLCore::HttpHandle handle, LLCore::HttpResponse * response);
- virtual void processData(LLCore::BufferArray * body, U8 * data, S32 data_size) = 0;
+ virtual void processData(LLCore::BufferArray * body, S32 body_offset, U8 * data, S32 data_size) = 0;
virtual void processFailure(LLCore::HttpStatus status) = 0;
public:
LLVolumeParams mMeshParams;
bool mProcessed;
- LLCore::HttpHandle mHttpHandle;
+ LLCore::HttpHandle mHttpHandle;
+ U32 mOffset;
+ U32 mRequestedBytes;
};
@@ -551,8 +558,8 @@ class LLMeshHeaderHandler : public LLMeshHandlerBase
{
public:
LOG_CLASS(LLMeshHeaderHandler);
- LLMeshHeaderHandler(const LLVolumeParams & mesh_params)
- : LLMeshHandlerBase()
+ LLMeshHeaderHandler(const LLVolumeParams & mesh_params, U32 offset, U32 requested_bytes)
+ : LLMeshHandlerBase(offset, requested_bytes)
{
mMeshParams = mesh_params;
LLMeshRepoThread::incActiveHeaderRequests();
@@ -564,7 +571,7 @@ protected:
void operator=(const LLMeshHeaderHandler &); // Not defined
public:
- virtual void processData(LLCore::BufferArray * body, U8 * data, S32 data_size);
+ virtual void processData(LLCore::BufferArray * body, S32 body_offset, U8 * data, S32 data_size);
virtual void processFailure(LLCore::HttpStatus status);
};
@@ -573,17 +580,16 @@ public:
//
// Thread: repo
class LLMeshLODHandler : public LLMeshHandlerBase
- {
+{
public:
+ LOG_CLASS(LLMeshLODHandler);
LLMeshLODHandler(const LLVolumeParams & mesh_params, S32 lod, U32 offset, U32 requested_bytes)
- : LLMeshHandlerBase(),
- mLOD(lod),
- mRequestedBytes(requested_bytes),
- mOffset(offset)
+ : LLMeshHandlerBase(offset, requested_bytes),
+ mLOD(lod)
{
- mMeshParams = mesh_params;
- LLMeshRepoThread::incActiveLODRequests();
- }
+ mMeshParams = mesh_params;
+ LLMeshRepoThread::incActiveLODRequests();
+ }
virtual ~LLMeshLODHandler();
protected:
@@ -591,13 +597,11 @@ protected:
void operator=(const LLMeshLODHandler &); // Not defined
public:
- virtual void processData(LLCore::BufferArray * body, U8 * data, S32 data_size);
+ virtual void processData(LLCore::BufferArray * body, S32 body_offset, U8 * data, S32 data_size);
virtual void processFailure(LLCore::HttpStatus status);
public:
S32 mLOD;
- U32 mRequestedBytes;
- U32 mOffset;
};
@@ -605,14 +609,12 @@ public:
//
// Thread: repo
class LLMeshSkinInfoHandler : public LLMeshHandlerBase
- {
+{
public:
LOG_CLASS(LLMeshSkinInfoHandler);
- LLMeshSkinInfoHandler(const LLUUID& id, U32 offset, U32 size)
- : LLMeshHandlerBase(),
- mMeshID(id),
- mRequestedBytes(size),
- mOffset(offset)
+ LLMeshSkinInfoHandler(const LLUUID& id, U32 offset, U32 requested_bytes)
+ : LLMeshHandlerBase(offset, requested_bytes),
+ mMeshID(id)
{}
virtual ~LLMeshSkinInfoHandler();
@@ -621,13 +623,11 @@ protected:
void operator=(const LLMeshSkinInfoHandler &); // Not defined
public:
- virtual void processData(LLCore::BufferArray * body, U8 * data, S32 data_size);
+ virtual void processData(LLCore::BufferArray * body, S32 body_offset, U8 * data, S32 data_size);
virtual void processFailure(LLCore::HttpStatus status);
public:
LLUUID mMeshID;
- U32 mRequestedBytes;
- U32 mOffset;
};
@@ -635,14 +635,12 @@ public:
//
// Thread: repo
class LLMeshDecompositionHandler : public LLMeshHandlerBase
- {
+{
public:
LOG_CLASS(LLMeshDecompositionHandler);
- LLMeshDecompositionHandler(const LLUUID& id, U32 offset, U32 size)
- : LLMeshHandlerBase(),
- mMeshID(id),
- mRequestedBytes(size),
- mOffset(offset)
+ LLMeshDecompositionHandler(const LLUUID& id, U32 offset, U32 requested_bytes)
+ : LLMeshHandlerBase(offset, requested_bytes),
+ mMeshID(id)
{}
virtual ~LLMeshDecompositionHandler();
@@ -651,13 +649,11 @@ protected:
void operator=(const LLMeshDecompositionHandler &); // Not defined
public:
- virtual void processData(LLCore::BufferArray * body, U8 * data, S32 data_size);
+ virtual void processData(LLCore::BufferArray * body, S32 body_offset, U8 * data, S32 data_size);
virtual void processFailure(LLCore::HttpStatus status);
public:
LLUUID mMeshID;
- U32 mRequestedBytes;
- U32 mOffset;
};
@@ -665,14 +661,12 @@ public:
//
// Thread: repo
class LLMeshPhysicsShapeHandler : public LLMeshHandlerBase
- {
+{
public:
LOG_CLASS(LLMeshPhysicsShapeHandler);
- LLMeshPhysicsShapeHandler(const LLUUID& id, U32 offset, U32 size)
- : LLMeshHandlerBase(),
- mMeshID(id),
- mRequestedBytes(size),
- mOffset(offset)
+ LLMeshPhysicsShapeHandler(const LLUUID& id, U32 offset, U32 requested_bytes)
+ : LLMeshHandlerBase(offset, requested_bytes),
+ mMeshID(id)
{}
virtual ~LLMeshPhysicsShapeHandler();
@@ -681,13 +675,11 @@ protected:
void operator=(const LLMeshPhysicsShapeHandler &); // Not defined
public:
- virtual void processData(LLCore::BufferArray * body, U8 * data, S32 data_size);
+ virtual void processData(LLCore::BufferArray * body, S32 body_offset, U8 * data, S32 data_size);
virtual void processFailure(LLCore::HttpStatus status);
public:
LLUUID mMeshID;
- U32 mRequestedBytes;
- U32 mOffset;
};
@@ -713,8 +705,8 @@ void log_upload_error(LLCore::HttpStatus status, const LLSD& content,
LL_WARNS(LOG_MESH) << "error: " << err << LL_ENDL;
LL_WARNS(LOG_MESH) << " mesh upload failed, stage '" << stage
<< "', error '" << err["error"].asString()
- << "', message '" << err["message"].asString()
- << "', id '" << err["identifier"].asString()
+ << "', message '" << err["message"].asString()
+ << "', id '" << err["identifier"].asString()
<< "'" << LL_ENDL;
if (err.has("errors"))
{
@@ -754,7 +746,9 @@ LLMeshRepoThread::LLMeshRepoThread()
mHttpLargePolicyClass(LLCore::HttpRequest::DEFAULT_POLICY_ID),
mHttpPriority(0),
mGetMeshVersion(2)
- {
+{
+ LLAppCoreHttp & app_core_http(LLAppViewer::instance()->getAppCoreHttp());
+
mMutex = new LLMutex(NULL);
mHeaderMutex = new LLMutex(NULL);
mSignal = new LLCondition(NULL);
@@ -766,15 +760,15 @@ LLMeshRepoThread::LLMeshRepoThread()
mHttpLargeOptions->setTransferTimeout(LARGE_MESH_XFER_TIMEOUT);
mHttpLargeOptions->setUseRetryAfter(gSavedSettings.getBOOL("MeshUseHttpRetryAfter"));
mHttpHeaders = new LLCore::HttpHeaders;
- mHttpHeaders->append("Accept", "application/vnd.ll.mesh");
- mHttpPolicyClass = LLAppViewer::instance()->getAppCoreHttp().getPolicy(LLAppCoreHttp::AP_MESH2);
- mHttpLegacyPolicyClass = LLAppViewer::instance()->getAppCoreHttp().getPolicy(LLAppCoreHttp::AP_MESH1);
- mHttpLargePolicyClass = LLAppViewer::instance()->getAppCoreHttp().getPolicy(LLAppCoreHttp::AP_LARGE_MESH);
- }
+ mHttpHeaders->append(HTTP_OUT_HEADER_ACCEPT, HTTP_CONTENT_VND_LL_MESH);
+ mHttpPolicyClass = app_core_http.getPolicy(LLAppCoreHttp::AP_MESH2);
+ mHttpLegacyPolicyClass = app_core_http.getPolicy(LLAppCoreHttp::AP_MESH1);
+ mHttpLargePolicyClass = app_core_http.getPolicy(LLAppCoreHttp::AP_LARGE_MESH);
+}
LLMeshRepoThread::~LLMeshRepoThread()
- {
+{
LL_INFOS(LOG_MESH) << "Small GETs issued: " << LLMeshRepository::sHTTPRequestCount
<< ", Large GETs issued: " << LLMeshRepository::sHTTPLargeRequestCount
<< ", Max Lock Holdoffs: " << LLMeshRepository::sMaxLockHoldoffs
@@ -785,23 +779,23 @@ LLMeshRepoThread::~LLMeshRepoThread()
++iter)
{
delete *iter;
- }
+ }
mHttpRequestSet.clear();
if (mHttpHeaders)
- {
+ {
mHttpHeaders->release();
mHttpHeaders = NULL;
- }
+ }
if (mHttpOptions)
- {
+ {
mHttpOptions->release();
mHttpOptions = NULL;
- }
+ }
if (mHttpLargeOptions)
-{
+ {
mHttpLargeOptions->release();
mHttpLargeOptions = NULL;
-}
+ }
delete mHttpRequest;
mHttpRequest = NULL;
delete mMutex;
@@ -846,48 +840,49 @@ void LLMeshRepoThread::run()
{
// Dispatch all HttpHandler notifications
mHttpRequest->update(0L);
- }
+ }
sRequestWaterLevel = mHttpRequestSet.size(); // Stats data update
// NOTE: order of queue processing intentionally favors LOD requests over header requests
while (!mLODReqQ.empty() && mHttpRequestSet.size() < sRequestHighWater)
- {
+ {
if (! mMutex)
- {
+ {
break;
}
- mMutex->lock();
- LODRequest req = mLODReqQ.front();
- mLODReqQ.pop();
- LLMeshRepository::sLODProcessing--;
- mMutex->unlock();
+ 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);
+ {
+ mMutex->lock();
+ mLODReqQ.push(req);
++LLMeshRepository::sLODProcessing;
- mMutex->unlock();
- }
- }
+ mMutex->unlock();
+ }
+ }
while (!mHeaderReqQ.empty() && mHttpRequestSet.size() < sRequestHighWater)
- {
+ {
if (! mMutex)
- {
+ {
break;
}
- mMutex->lock();
- HeaderRequest req = mHeaderReqQ.front();
- mHeaderReqQ.pop();
- mMutex->unlock();
+ mMutex->lock();
+ HeaderRequest req = mHeaderReqQ.front();
+ mHeaderReqQ.pop();
+ mMutex->unlock();
if (!fetchMeshHeader(req.mMeshParams))//failed, resubmit
- {
- mMutex->lock();
- mHeaderReqQ.push(req) ;
- mMutex->unlock();
- }
- }
+ {
+ 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
@@ -983,7 +978,7 @@ void LLMeshRepoThread::run()
}
}
mMutex->unlock();
- }
+ }
// For dev purposes only. A dynamic change could make this false
// and that shouldn't assert.
@@ -1131,6 +1126,9 @@ LLCore::HttpHandle LLMeshRepoThread::getByteRange(const std::string & url, int c
size_t offset, size_t len,
LLCore::HttpHandler * handler)
{
+ // Also used in lltexturefetch.cpp
+ static LLCachedControl<bool> disable_range_req(gSavedSettings, "HttpRangeRequestsDisable", false);
+
LLCore::HttpHandle handle(LLCORE_HTTP_HANDLE_INVALID);
if (len < LARGE_MESH_FETCH_THRESHOLD)
@@ -1140,8 +1138,8 @@ LLCore::HttpHandle LLMeshRepoThread::getByteRange(const std::string & url, int c
: mHttpLegacyPolicyClass),
mHttpPriority,
url,
- offset,
- len,
+ (disable_range_req ? size_t(0) : offset),
+ (disable_range_req ? size_t(0) : len),
mHttpOptions,
mHttpHeaders,
handler);
@@ -1155,8 +1153,8 @@ LLCore::HttpHandle LLMeshRepoThread::getByteRange(const std::string & url, int c
handle = mHttpRequest->requestGetByteRange(mHttpLargePolicyClass,
mHttpPriority,
url,
- offset,
- len,
+ (disable_range_req ? size_t(0) : offset),
+ (disable_range_req ? size_t(0) : len),
mHttpLargeOptions,
mHttpHeaders,
handler);
@@ -1250,7 +1248,6 @@ bool LLMeshRepoThread::fetchMeshSkinInfo(const LLUUID& mesh_id)
<< LL_ENDL;
delete handler;
ret = false;
-
}
else
{
@@ -1527,7 +1524,7 @@ bool LLMeshRepoThread::fetchMeshHeader(const LLVolumeParams& mesh_params)
//within the first 4KB
//NOTE -- this will break of headers ever exceed 4KB
- LLMeshHeaderHandler * handler = new LLMeshHeaderHandler(mesh_params);
+ LLMeshHeaderHandler * handler = new LLMeshHeaderHandler(mesh_params, 0, MESH_HEADER_SIZE);
LLCore::HttpHandle handle = getByteRange(http_url, cap_version, 0, MESH_HEADER_SIZE, handler);
if (LLCORE_HTTP_HANDLE_INVALID == handle)
{
@@ -1860,7 +1857,7 @@ LLMeshUploadThread::LLMeshUploadThread(LLMeshUploadThread::instance_list& data,
bool upload_skin, bool upload_joints, const std::string & upload_url, bool do_upload,
LLHandle<LLWholeModelFeeObserver> fee_observer,
LLHandle<LLWholeModelUploadObserver> upload_observer)
-: LLThread("mesh upload"),
+ : LLThread("mesh upload"),
LLCore::HttpHandler(),
mDiscarded(false),
mDoUpload(do_upload),
@@ -1890,7 +1887,7 @@ LLMeshUploadThread::LLMeshUploadThread(LLMeshUploadThread::instance_list& data,
mHttpOptions->setUseRetryAfter(gSavedSettings.getBOOL("MeshUseHttpRetryAfter"));
mHttpOptions->setRetries(UPLOAD_RETRY_LIMIT);
mHttpHeaders = new LLCore::HttpHeaders;
- mHttpHeaders->append("Content-Type", "application/llsd+xml");
+ mHttpHeaders->append(HTTP_OUT_HEADER_CONTENT_TYPE, HTTP_CONTENT_LLSD_XML);
mHttpPolicyClass = LLAppViewer::instance()->getAppCoreHttp().getPolicy(LLAppCoreHttp::AP_UPLOADS);
mHttpPriority = 0;
}
@@ -2240,21 +2237,17 @@ void LLMeshUploadThread::doWholeModelUpload()
mModelData = LLSD::emptyMap();
wholeModelToLLSD(mModelData, true);
LLSD body = mModelData["asset_resources"];
- dump_llsd_to_file(body,make_dump_name("whole_model_body_",dump_num));
-
- LLCore::BufferArray * ba = new LLCore::BufferArray;
- LLCore::BufferArrayStream bas(ba);
- LLSDSerialize::toXML(body, bas);
- // LLSDSerialize::toXML(mModelData, bas); // <- Enabling this will generate a convenient upload error
- LLCore::HttpHandle handle = mHttpRequest->requestPost(mHttpPolicyClass,
- mHttpPriority,
- mWholeModelUploadURL,
- ba,
- mHttpOptions,
- mHttpHeaders,
- this);
- ba->release();
-
+
+ dump_llsd_to_file(body, make_dump_name("whole_model_body_", dump_num));
+
+ LLCore::HttpHandle handle = LLCoreHttpUtil::requestPostWithLLSD(mHttpRequest,
+ mHttpPolicyClass,
+ mHttpPriority,
+ mWholeModelUploadURL,
+ body,
+ mHttpOptions,
+ mHttpHeaders,
+ this);
if (LLCORE_HTTP_HANDLE_INVALID == handle)
{
mHttpStatus = mHttpRequest->getStatus();
@@ -2271,7 +2264,7 @@ void LLMeshUploadThread::doWholeModelUpload()
mHttpRequest->update(0);
while (! LLApp::isQuitting() && ! finished() && ! isDiscarded())
- {
+ {
ms_sleep(sleep_time);
sleep_time = llmin(250U, sleep_time + sleep_time);
mHttpRequest->update(0);
@@ -2287,7 +2280,7 @@ void LLMeshUploadThread::doWholeModelUpload()
}
}
}
- }
+}
void LLMeshUploadThread::requestWholeModelFee()
{
@@ -2298,19 +2291,14 @@ void LLMeshUploadThread::requestWholeModelFee()
mModelData = LLSD::emptyMap();
wholeModelToLLSD(mModelData, false);
dump_llsd_to_file(mModelData, make_dump_name("whole_model_fee_request_", dump_num));
-
- LLCore::BufferArray * ba = new LLCore::BufferArray;
- LLCore::BufferArrayStream bas(ba);
- LLSDSerialize::toXML(mModelData, bas);
-
- LLCore::HttpHandle handle = mHttpRequest->requestPost(mHttpPolicyClass,
- mHttpPriority,
- mWholeModelFeeCapability,
- ba,
- mHttpOptions,
- mHttpHeaders,
- this);
- ba->release();
+ LLCore::HttpHandle handle = LLCoreHttpUtil::requestPostWithLLSD(mHttpRequest,
+ mHttpPolicyClass,
+ mHttpPriority,
+ mWholeModelFeeCapability,
+ mModelData,
+ mHttpOptions,
+ mHttpHeaders,
+ this);
if (LLCORE_HTTP_HANDLE_INVALID == handle)
{
mHttpStatus = mHttpRequest->getStatus();
@@ -2318,7 +2306,7 @@ void LLMeshUploadThread::requestWholeModelFee()
LL_WARNS(LOG_MESH) << "Couldn't issue request for model fee. Reason: " << mHttpStatus.toString()
<< " (" << mHttpStatus.toTerseString() << ")"
<< LL_ENDL;
- }
+ }
else
{
U32 sleep_time(10);
@@ -2335,7 +2323,7 @@ void LLMeshUploadThread::requestWholeModelFee()
LL_DEBUGS(LOG_MESH) << "Mesh fee query operation discarded." << LL_ENDL;
}
}
- }
+}
// Does completion duty for both fee queries and actual uploads.
@@ -2383,17 +2371,13 @@ void LLMeshUploadThread::onCompleted(LLCore::HttpHandle handle, LLCore::HttpResp
}
else
{
- LLCore::BufferArray * ba(response->getBody());
- if (ba && ba->size())
- {
- LLCore::BufferArrayStream bas(ba);
- LLSDSerialize::fromXML(body, bas);
-}
+ // *TODO: handle error in conversion process
+ LLCoreHttpUtil::responseToLLSD(response, true, body);
}
dump_llsd_to_file(body, make_dump_name("whole_model_upload_response_", dump_num));
if (body["state"].asString() == "complete")
-{
+ {
// requested "mesh" asset type isn't actually the type
// of the resultant object, fix it up here.
mModelData["asset_type"] = "object";
@@ -2446,18 +2430,14 @@ void LLMeshUploadThread::onCompleted(LLCore::HttpHandle handle, LLCore::HttpResp
body = llsd_from_file("fake_upload_error.xml");
}
else
- {
- LLCore::BufferArray * ba(response->getBody());
- if (ba && ba->size())
- {
- LLCore::BufferArrayStream bas(ba);
- LLSDSerialize::fromXML(body, bas);
- }
- }
+ {
+ // *TODO: handle error in conversion process
+ LLCoreHttpUtil::responseToLLSD(response, true, body);
+ }
dump_llsd_to_file(body, make_dump_name("whole_model_fee_response_", dump_num));
if (body["state"].asString() == "upload")
- {
+ {
mWholeModelUploadURL = body["uploader"].asString();
if (observer)
@@ -2543,18 +2523,18 @@ void LLMeshRepoThread::notifyLoadedMeshes()
skin_info_q.swap(mSkinInfoQ);
}
if (! mDecompositionQ.empty())
- {
+ {
decomp_q.swap(mDecompositionQ);
- }
+ }
mMutex->unlock();
// Process the elements free of the lock
while (! skin_info_q.empty())
- {
+ {
gMeshRepo.notifySkinInfoReceived(skin_info_q.front());
skin_info_q.pop_front();
- }
+ }
while (! decomp_q.empty())
{
@@ -2648,6 +2628,17 @@ void LLMeshRepository::cacheOutgoingMesh(LLMeshUploadData& data, LLSD& header)
}
+// Handle failed or successful requests for mesh assets.
+//
+// Support for 200 responses was added for several reasons. One,
+// a service or cache can ignore range headers and give us a
+// 200 with full asset should it elect to. We also support
+// a debug flag which disables range requests for those very
+// few users that have some sort of problem with their networking
+// services. But the 200 response handling is suboptimal: rather
+// than cache the whole asset, we just extract the part that would
+// have been sent in a 206 and process that. Inefficient but these
+// are cases far off the norm.
void LLMeshHandlerBase::onCompleted(LLCore::HttpHandle handle, LLCore::HttpResponse * response)
{
mProcessed = true;
@@ -2676,35 +2667,78 @@ void LLMeshHandlerBase::onCompleted(LLCore::HttpHandle handle, LLCore::HttpRespo
// rather than partial) and 416 (request completely unsatisfyable).
// Always been exposed to these but are less likely here where
// speculative loads aren't done.
- static const LLCore::HttpStatus par_status(HTTP_PARTIAL_CONTENT);
+ LLCore::BufferArray * body(response->getBody());
+ S32 body_offset(0);
+ U8 * data(NULL);
+ S32 data_size(body ? body->size() : 0);
- if (par_status != status)
+ if (data_size > 0)
{
- LL_WARNS_ONCE(LOG_MESH) << "Non-206 successful status received for fetch: "
- << status.toTerseString() << LL_ENDL;
- }
+ static const LLCore::HttpStatus par_status(HTTP_PARTIAL_CONTENT);
+
+ unsigned int offset(0), length(0), full_length(0);
+
+ if (par_status == status)
+ {
+ // 206 case
+ response->getRange(&offset, &length, &full_length);
+ if (! offset && ! length)
+ {
+ // This is the case where we receive a 206 status but
+ // there wasn't a useful Content-Range header in the response.
+ // This could be because it was badly formatted but is more
+ // likely due to capabilities services which scrub headers
+ // from responses. Assume we got what we asked for...`
+ // length = data_size;
+ offset = mOffset;
+ }
+ }
+ else
+ {
+ // 200 case, typically
+ offset = 0;
+ }
- LLCore::BufferArray * body(response->getBody());
- S32 data_size(body ? body->size() : 0);
- U8 * data(NULL);
+ // *DEBUG: To test validation below
+ // offset += 1;
- if (data_size > 0)
- {
+ // Validate that what we think we received is consistent with
+ // what we've asked for. I.e. first byte we wanted lies somewhere
+ // in the response.
+ if (offset > mOffset
+ || (offset + data_size) <= mOffset
+ || (mOffset - offset) >= data_size)
+ {
+ // No overlap with requested range. Fail request with
+ // suitable error. Shouldn't happen unless server/cache/ISP
+ // is doing something awful.
+ LL_WARNS(LOG_MESH) << "Mesh response (bytes ["
+ << offset << ".." << (offset + length - 1)
+ << "]) didn't overlap with request's origin (bytes ["
+ << mOffset << ".." << (mOffset + mRequestedBytes - 1)
+ << "])." << LL_ENDL;
+ processFailure(LLCore::HttpStatus(LLCore::HttpStatus::LLCORE, LLCore::HE_INV_CONTENT_RANGE_HDR));
+ ++LLMeshRepository::sHTTPErrorCount;
+ goto common_exit;
+ }
+
// *TODO: Try to get rid of data copying and add interfaces
// that support BufferArray directly. Introduce a two-phase
// handler, optional first that takes a body, fallback second
// that requires a temporary allocation and data copy.
- data = new U8[data_size];
- body->read(0, (char *) data, data_size);
+ body_offset = mOffset - offset;
+ data = new U8[data_size - body_offset];
+ body->read(body_offset, (char *) data, data_size - body_offset);
LLMeshRepository::sBytesReceived += data_size;
}
- processData(body, data, data_size);
+ processData(body, body_offset, data, data_size - body_offset);
delete [] data;
}
// Release handler
+common_exit:
gMeshRepo.mThread->mHttpRequestSet.erase(this);
delete this; // Must be last statement
}
@@ -2739,9 +2773,10 @@ void LLMeshHeaderHandler::processFailure(LLCore::HttpStatus status)
{
gMeshRepo.mThread->mUnavailableQ.push(LLMeshRepoThread::LODRequest(mMeshParams, i));
}
- }
+}
-void LLMeshHeaderHandler::processData(LLCore::BufferArray * body, U8 * data, S32 data_size)
+void LLMeshHeaderHandler::processData(LLCore::BufferArray * /* body */, S32 /* body_offset */,
+ U8 * data, S32 data_size)
{
LLUUID mesh_id = mMeshParams.getSculptID();
bool success = (! MESH_HEADER_PROCESS_FAILED) && gMeshRepo.mThread->headerReceived(mMeshParams, data, data_size);
@@ -2756,12 +2791,12 @@ void LLMeshHeaderHandler::processData(LLCore::BufferArray * body, U8 * data, S32
// Can't get the header so none of the LODs will be available
LLMutexLock lock(gMeshRepo.mThread->mMutex);
for (int i(0); i < 4; ++i)
- {
+ {
gMeshRepo.mThread->mUnavailableQ.push(LLMeshRepoThread::LODRequest(mMeshParams, i));
- }
}
+ }
else if (data && data_size > 0)
- {
+ {
// header was successfully retrieved from sim, cache in vfs
LLSD header = gMeshRepo.mThread->mMeshHeader[mesh_id];
@@ -2774,11 +2809,11 @@ void LLMeshHeaderHandler::processData(LLCore::BufferArray * body, U8 * data, S32
S32 lod_bytes = 0;
for (U32 i = 0; i < LLModel::LOD_PHYSICS; ++i)
- {
+ {
// figure out how many bytes we'll need to reserve in the file
const std::string & lod_name = header_lod[i];
lod_bytes = llmax(lod_bytes, header[lod_name]["offset"].asInteger()+header[lod_name]["size"].asInteger());
- }
+ }
// just in case skin info or decomposition is at the end of the file (which it shouldn't be)
lod_bytes = llmax(lod_bytes, header["skin"]["offset"].asInteger() + header["skin"]["size"].asInteger());
@@ -2794,7 +2829,7 @@ void LLMeshHeaderHandler::processData(LLCore::BufferArray * body, U8 * data, S32
LLVFile file(gVFS, mesh_id, LLAssetType::AT_MESH, LLVFile::WRITE);
if (file.getMaxSize() >= bytes || file.setMaxSize(bytes))
- {
+ {
LLMeshRepository::sCacheBytesWritten += data_size;
++LLMeshRepository::sCacheWrites;
@@ -2805,19 +2840,19 @@ void LLMeshHeaderHandler::processData(LLCore::BufferArray * body, U8 * data, S32
memset(block, 0, sizeof(block));
while (bytes-file.tell() > sizeof(block))
- {
+ {
file.write(block, sizeof(block));
- }
+ }
S32 remaining = bytes-file.tell();
if (remaining > 0)
- {
+ {
file.write(block, remaining);
}
}
}
}
- }
+}
LLMeshLODHandler::~LLMeshLODHandler()
{
@@ -2843,8 +2878,9 @@ void LLMeshLODHandler::processFailure(LLCore::HttpStatus status)
gMeshRepo.mThread->mUnavailableQ.push(LLMeshRepoThread::LODRequest(mMeshParams, mLOD));
}
-void LLMeshLODHandler::processData(LLCore::BufferArray * body, U8 * data, S32 data_size)
- {
+void LLMeshLODHandler::processData(LLCore::BufferArray * /* body */, S32 /* body_offset */,
+ U8 * data, S32 data_size)
+{
if ((! MESH_LOD_PROCESS_FAILED) && gMeshRepo.mThread->lodReceived(mMeshParams, mLOD, data, data_size))
{
//good fetch from sim, write to VFS for caching
@@ -2860,7 +2896,7 @@ void LLMeshLODHandler::processData(LLCore::BufferArray * body, U8 * data, S32 da
LLMeshRepository::sCacheBytesWritten += size;
++LLMeshRepository::sCacheWrites;
}
- }
+ }
else
{
LL_WARNS(LOG_MESH) << "Error during mesh LOD processing. ID: " << mMeshParams.getSculptID()
@@ -2872,12 +2908,12 @@ void LLMeshLODHandler::processData(LLCore::BufferArray * body, U8 * data, S32 da
}
LLMeshSkinInfoHandler::~LLMeshSkinInfoHandler()
- {
- llassert(mProcessed);
- }
+{
+ llassert(mProcessed);
+}
void LLMeshSkinInfoHandler::processFailure(LLCore::HttpStatus status)
- {
+{
LL_WARNS(LOG_MESH) << "Error during mesh skin info handling. ID: " << mMeshID
<< ", Reason: " << status.toString()
<< " (" << status.toTerseString() << "). Not retrying."
@@ -2885,10 +2921,11 @@ void LLMeshSkinInfoHandler::processFailure(LLCore::HttpStatus status)
// *TODO: Mark mesh unavailable on error. For now, simply leave
// request unfulfilled rather than retry forever.
- }
+}
-void LLMeshSkinInfoHandler::processData(LLCore::BufferArray * body, U8 * data, S32 data_size)
- {
+void LLMeshSkinInfoHandler::processData(LLCore::BufferArray * /* body */, S32 /* body_offset */,
+ U8 * data, S32 data_size)
+{
if ((! MESH_SKIN_INFO_PROCESS_FAILED) && gMeshRepo.mThread->skinInfoReceived(mMeshID, data, data_size))
{
//good fetch from sim, write to VFS for caching
@@ -2916,20 +2953,21 @@ void LLMeshSkinInfoHandler::processData(LLCore::BufferArray * body, U8 * data, S
LLMeshDecompositionHandler::~LLMeshDecompositionHandler()
{
- llassert(mProcessed);
+ llassert(mProcessed);
}
void LLMeshDecompositionHandler::processFailure(LLCore::HttpStatus status)
- {
+{
LL_WARNS(LOG_MESH) << "Error during mesh decomposition handling. ID: " << mMeshID
<< ", Reason: " << status.toString()
<< " (" << status.toTerseString() << "). Not retrying."
<< LL_ENDL;
// *TODO: Mark mesh unavailable on error. For now, simply leave
// request unfulfilled rather than retry forever.
- }
+}
-void LLMeshDecompositionHandler::processData(LLCore::BufferArray * body, U8 * data, S32 data_size)
+void LLMeshDecompositionHandler::processData(LLCore::BufferArray * /* body */, S32 /* body_offset */,
+ U8 * data, S32 data_size)
{
if ((! MESH_DECOMP_PROCESS_FAILED) && gMeshRepo.mThread->decompositionReceived(mMeshID, data, data_size))
{
@@ -2946,34 +2984,35 @@ void LLMeshDecompositionHandler::processData(LLCore::BufferArray * body, U8 * da
file.seek(offset);
file.write(data, size);
}
- }
- else
- {
+ }
+ else
+ {
LL_WARNS(LOG_MESH) << "Error during mesh decomposition processing. ID: " << mMeshID
<< ", Unknown reason. Not retrying."
<< LL_ENDL;
// *TODO: Mark mesh unavailable on error
- }
}
+}
LLMeshPhysicsShapeHandler::~LLMeshPhysicsShapeHandler()
- {
- llassert(mProcessed);
- }
+{
+ llassert(mProcessed);
+}
void LLMeshPhysicsShapeHandler::processFailure(LLCore::HttpStatus status)
- {
+{
LL_WARNS(LOG_MESH) << "Error during mesh physics shape handling. ID: " << mMeshID
<< ", Reason: " << status.toString()
<< " (" << status.toTerseString() << "). Not retrying."
<< LL_ENDL;
// *TODO: Mark mesh unavailable on error
- }
+}
-void LLMeshPhysicsShapeHandler::processData(LLCore::BufferArray * body, U8 * data, S32 data_size)
- {
+void LLMeshPhysicsShapeHandler::processData(LLCore::BufferArray * /* body */, S32 /* body_offset */,
+ U8 * data, S32 data_size)
+{
if ((! MESH_PHYS_SHAPE_PROCESS_FAILED) && gMeshRepo.mThread->physicsShapeReceived(mMeshID, data, data_size))
- {
+ {
// good fetch from sim, write to VFS for caching
LLVFile file(gVFS, mMeshID, LLAssetType::AT_MESH, LLVFile::WRITE);
@@ -2981,13 +3020,13 @@ void LLMeshPhysicsShapeHandler::processData(LLCore::BufferArray * body, U8 * dat
S32 size = mRequestedBytes;
if (file.getSize() >= offset+size)
- {
+ {
LLMeshRepository::sCacheBytesWritten += size;
++LLMeshRepository::sCacheWrites;
file.seek(offset);
file.write(data, size);
- }
}
+ }
else
{
LL_WARNS(LOG_MESH) << "Error during mesh physics shape processing. ID: " << mMeshID
@@ -3187,7 +3226,7 @@ void LLMeshRepository::notifyLoadedMeshes()
if (1 == mGetMeshVersion)
{
// Legacy GetMesh operation with high connection concurrency
- LLMeshRepoThread::sMaxConcurrentRequests = gSavedSettings.getU32("MeshMaxConcurrentRequests");
+ LLMeshRepoThread::sMaxConcurrentRequests = gSavedSettings.getU32("MeshMaxConcurrentRequests");
LLMeshRepoThread::sRequestHighWater = llclamp(2 * S32(LLMeshRepoThread::sMaxConcurrentRequests),
REQUEST_HIGH_WATER_MIN,
REQUEST_HIGH_WATER_MAX);
@@ -3198,9 +3237,15 @@ void LLMeshRepository::notifyLoadedMeshes()
else
{
// GetMesh2 operation with keepalives, etc. With pipelining,
- // we'll increase this.
+ // we'll increase this. See llappcorehttp and llcorehttp for
+ // discussion on connection strategies.
+ LLAppCoreHttp & app_core_http(LLAppViewer::instance()->getAppCoreHttp());
+ S32 scale(app_core_http.isPipelined(LLAppCoreHttp::AP_MESH2)
+ ? (2 * LLAppCoreHttp::PIPELINING_DEPTH)
+ : 5);
+
LLMeshRepoThread::sMaxConcurrentRequests = gSavedSettings.getU32("Mesh2MaxConcurrentRequests");
- LLMeshRepoThread::sRequestHighWater = llclamp(5 * S32(LLMeshRepoThread::sMaxConcurrentRequests),
+ LLMeshRepoThread::sRequestHighWater = llclamp(scale * S32(LLMeshRepoThread::sMaxConcurrentRequests),
REQUEST2_HIGH_WATER_MIN,
REQUEST2_HIGH_WATER_MAX);
LLMeshRepoThread::sRequestLowWater = llclamp(LLMeshRepoThread::sRequestHighWater / 2,
@@ -3300,18 +3345,18 @@ void LLMeshRepository::notifyLoadedMeshes()
// If we can't get the locks, skip and pick this up later.
++hold_offs;
sMaxLockHoldoffs = llmax(sMaxLockHoldoffs, hold_offs);
- return;
- }
+ return;
+ }
hold_offs = 0;
if (gAgent.getRegion())
{
// Update capability urls
- static std::string region_name("never name a region this");
+ static std::string region_name("never name a region this");
- if (gAgent.getRegion()->getName() != region_name && gAgent.getRegion()->capabilitiesReceived())
- {
- region_name = gAgent.getRegion()->getName();
+ if (gAgent.getRegion()->getName() != region_name && gAgent.getRegion()->capabilitiesReceived())
+ {
+ region_name = gAgent.getRegion()->getName();
const bool use_v1(gSavedSettings.getBOOL("MeshUseGetMesh1"));
const std::string mesh1(gAgent.getRegion()->getCapability("GetMesh"));
const std::string mesh2(gAgent.getRegion()->getCapability("GetMesh2"));
@@ -3322,8 +3367,8 @@ void LLMeshRepository::notifyLoadedMeshes()
<< ", GetMesh: " << mesh1
<< ", using version: " << mGetMeshVersion
<< LL_ENDL;
+ }
}
- }
//popup queued error messages from background threads
while (!mUploadErrorQ.empty())
@@ -3338,46 +3383,46 @@ void LLMeshRepository::notifyLoadedMeshes()
S32 push_count = LLMeshRepoThread::sRequestHighWater - active_count;
if (mPendingRequests.size() > push_count)
- {
+ {
// More requests than the high-water limit allows so
// sort and forward the most important.
- //calculate "score" for pending requests
+ //calculate "score" for pending requests
- //create score map
- std::map<LLUUID, F32> score_map;
+ //create score map
+ std::map<LLUUID, F32> score_map;
- for (U32 i = 0; i < 4; ++i)
- {
- for (mesh_load_map::iterator iter = mLoadingMeshes[i].begin(); iter != mLoadingMeshes[i].end(); ++iter)
+ for (U32 i = 0; i < 4; ++i)
{
- F32 max_score = 0.f;
- for (std::set<LLUUID>::iterator obj_iter = iter->second.begin(); obj_iter != iter->second.end(); ++obj_iter)
+ for (mesh_load_map::iterator iter = mLoadingMeshes[i].begin(); iter != mLoadingMeshes[i].end(); ++iter)
{
- LLViewerObject* object = gObjectList.findObject(*obj_iter);
-
- if (object)
+ F32 max_score = 0.f;
+ for (std::set<LLUUID>::iterator obj_iter = iter->second.begin(); obj_iter != iter->second.end(); ++obj_iter)
{
- LLDrawable* drawable = object->mDrawable;
- if (drawable)
+ LLViewerObject* object = gObjectList.findObject(*obj_iter);
+
+ if (object)
{
- F32 cur_score = drawable->getRadius()/llmax(drawable->mDistanceWRTCamera, 1.f);
- max_score = llmax(max_score, cur_score);
+ LLDrawable* drawable = object->mDrawable;
+ if (drawable)
+ {
+ F32 cur_score = drawable->getRadius()/llmax(drawable->mDistanceWRTCamera, 1.f);
+ max_score = llmax(max_score, cur_score);
+ }
}
}
- }
- score_map[iter->first.getSculptID()] = max_score;
+ score_map[iter->first.getSculptID()] = max_score;
+ }
}
- }
- //set "score" for pending requests
- for (std::vector<LLMeshRepoThread::LODRequest>::iterator iter = mPendingRequests.begin(); iter != mPendingRequests.end(); ++iter)
- {
- iter->mScore = score_map[iter->mMeshParams.getSculptID()];
- }
+ //set "score" for pending requests
+ for (std::vector<LLMeshRepoThread::LODRequest>::iterator iter = mPendingRequests.begin(); iter != mPendingRequests.end(); ++iter)
+ {
+ iter->mScore = score_map[iter->mMeshParams.getSculptID()];
+ }
- //sort by "score"
+ //sort by "score"
std::partial_sort(mPendingRequests.begin(), mPendingRequests.begin() + push_count,
mPendingRequests.end(), LLMeshRepoThread::CompareScoreGreater());
}
@@ -3588,7 +3633,6 @@ void LLMeshRepository::fetchPhysicsShape(const LLUUID& mesh_id)
}
}
}
-
}
LLModel::Decomposition* LLMeshRepository::getDecomposition(const LLUUID& mesh_id)