Texture fetch cleanup
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
/**
|
||||
/**
|
||||
* @file lltexturefetch.cpp
|
||||
* @brief Object which fetches textures from the cache and/or network
|
||||
*
|
||||
@@ -28,6 +28,9 @@
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include <boost/regex.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
|
||||
#include "llstl.h"
|
||||
#include "message.h"
|
||||
|
||||
@@ -249,9 +252,9 @@ private:
|
||||
LLFrameTimer mFetchTimer;
|
||||
LLTextureCache::handle_t mCacheReadHandle;
|
||||
LLTextureCache::handle_t mCacheWriteHandle;
|
||||
U8* mBuffer;
|
||||
S32 mBufferSize;
|
||||
std::vector<U8> mHttpBuffer;
|
||||
S32 mRequestedSize;
|
||||
S32 mRequestedOffset;
|
||||
S32 mDesiredSize;
|
||||
S32 mFileSize;
|
||||
S32 mCachedSize;
|
||||
@@ -297,16 +300,44 @@ class HTTPGetResponder : public LLHTTPClient::ResponderWithCompleted
|
||||
LOG_CLASS(HTTPGetResponder);
|
||||
public:
|
||||
HTTPGetResponder(LLTextureFetch* fetcher, const LLUUID& id, U64 startTime, S32 requestedSize, U32 offset, bool redir)
|
||||
: mFetcher(fetcher), mID(id), mStartTime(startTime), mRequestedSize(requestedSize), mOffset(offset), mFollowRedir(redir)
|
||||
: mFetcher(fetcher)
|
||||
, mID(id)
|
||||
, mStartTime(startTime)
|
||||
, mRequestedSize(requestedSize)
|
||||
, mRequestedOffset(offset)
|
||||
, mFollowRedir(redir)
|
||||
{
|
||||
}
|
||||
~HTTPGetResponder()
|
||||
{
|
||||
}
|
||||
|
||||
virtual AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return HTTPGetResponder_timeout; }
|
||||
/*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return HTTPGetResponder_timeout; }
|
||||
|
||||
virtual void completedRaw(U32 status, const std::string& reason,
|
||||
#if 0 //Apparently, SL never sends content-range and instead sends transfer-encoding: chunked, so disabling for now
|
||||
/*virtual*/ bool needsHeaders(void) const { return true; }
|
||||
|
||||
/*virtual*/ void completedHeaders(U32 status, std::string const& reason, AIHTTPReceivedHeaders const& headers) {
|
||||
llinfos << "Texture fetch HTTP status: " << status << llendl;
|
||||
llinfos << "Texture fetch headers: " << headers << llendl;
|
||||
//example: Content-Range: 1000-3979/3980 Content-Length: 2980
|
||||
static const boost::regex pattern("\\w*bytes\\w+(\\d+)-(\\d+)/(\\d+)");
|
||||
std::string rangehdr;
|
||||
if (headers.getFirstValue("content-range", rangehdr)){
|
||||
llinfos << "Have content-range header" <<llendl;
|
||||
boost::smatch match;
|
||||
llassert_always(boost::regex_match(rangehdr, match, pattern));
|
||||
llassert(match.length() == 3);
|
||||
|
||||
std::string lengthhdr;
|
||||
if(headers.getFirstValue("content-length",lengthhdr)) {
|
||||
//insert length checking
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/*virtual*/ void completedRaw(U32 status, const std::string& reason,
|
||||
const LLChannelDescriptors& channels,
|
||||
const buffer_ptr_t& buffer)
|
||||
{
|
||||
@@ -320,7 +351,7 @@ public:
|
||||
U64 timeNow = LLTimer::getTotalTime();
|
||||
mFetcher->mTextureInfo.setRequestType(mID, LLTextureInfoDetails::REQUEST_TYPE_HTTP);
|
||||
mFetcher->mTextureInfo.setRequestSize(mID, mRequestedSize);
|
||||
mFetcher->mTextureInfo.setRequestOffset(mID, mOffset);
|
||||
mFetcher->mTextureInfo.setRequestOffset(mID, mRequestedOffset);
|
||||
mFetcher->mTextureInfo.setRequestCompleteTimeAndLog(mID, timeNow);
|
||||
}
|
||||
|
||||
@@ -387,7 +418,7 @@ private:
|
||||
LLUUID mID;
|
||||
U64 mStartTime;
|
||||
S32 mRequestedSize;
|
||||
U32 mOffset;
|
||||
U32 mRequestedOffset;
|
||||
bool mFollowRedir;
|
||||
};
|
||||
|
||||
@@ -754,9 +785,8 @@ LLTextureFetchWorker::LLTextureFetchWorker(LLTextureFetch* fetcher,
|
||||
mDecodedDiscard(-1),
|
||||
mCacheReadHandle(LLTextureCache::nullHandle()),
|
||||
mCacheWriteHandle(LLTextureCache::nullHandle()),
|
||||
mBuffer(NULL),
|
||||
mBufferSize(0),
|
||||
mRequestedSize(0),
|
||||
mRequestedOffset(0),
|
||||
mDesiredSize(TEXTURE_CACHE_ENTRY_SIZE),
|
||||
mFileSize(0),
|
||||
mCachedSize(0),
|
||||
@@ -785,7 +815,7 @@ LLTextureFetchWorker::LLTextureFetchWorker(LLTextureFetch* fetcher,
|
||||
|
||||
calcWorkPriority();
|
||||
mType = host.isOk() ? LLImageBase::TYPE_AVATAR_BAKE : LLImageBase::TYPE_NORMAL;
|
||||
llinfos << "Create: " << mID << " mHost:" << host << " Discard=" << discard << " URL:"<< mUrl << llendl;
|
||||
//llinfos << "Create: " << mID << " mHost:" << host << " Discard=" << discard << " URL:"<< mUrl << llendl;
|
||||
if (!mFetcher->mDebugPause)
|
||||
{
|
||||
U32 work_priority = mWorkPriority | LLWorkerThread::PRIORITY_HIGH;
|
||||
@@ -916,9 +946,7 @@ void LLTextureFetchWorker::setImagePriority(F32 priority)
|
||||
|
||||
void LLTextureFetchWorker::resetFormattedData()
|
||||
{
|
||||
FREE_MEM(LLImageBase::getPrivatePool(), mBuffer);
|
||||
mBuffer = NULL;
|
||||
mBufferSize = 0;
|
||||
std::vector<U8>().swap(mHttpBuffer);
|
||||
if (mFormattedImage.notNull())
|
||||
{
|
||||
mFormattedImage->deleteData();
|
||||
@@ -990,15 +1018,14 @@ bool LLTextureFetchWorker::doWork(S32 param)
|
||||
mLoadedDiscard = -1;
|
||||
mDecodedDiscard = -1;
|
||||
mRequestedSize = 0;
|
||||
mRequestedOffset = 0;
|
||||
mFileSize = 0;
|
||||
mCachedSize = 0;
|
||||
mLoaded = FALSE;
|
||||
mSentRequest = UNSENT;
|
||||
mDecoded = FALSE;
|
||||
mWritten = FALSE;
|
||||
FREE_MEM(LLImageBase::getPrivatePool(), mBuffer);
|
||||
mBuffer = NULL;
|
||||
mBufferSize = 0;
|
||||
std::vector<U8>().swap(mHttpBuffer);
|
||||
mHaveAllData = FALSE;
|
||||
clearPackets(); // TODO: Shouldn't be necessary
|
||||
mCacheReadHandle = LLTextureCache::nullHandle();
|
||||
@@ -1288,14 +1315,11 @@ bool LLTextureFetchWorker::doWork(S32 param)
|
||||
return true ; //abort.
|
||||
}
|
||||
}
|
||||
resetFormattedData();
|
||||
cur_size = 0;
|
||||
}
|
||||
mRequestedSize = mDesiredSize;
|
||||
mRequestedDiscard = mDesiredDiscard;
|
||||
mRequestedSize -= cur_size;
|
||||
S32 offset = cur_size;
|
||||
mBufferSize = cur_size; // This will get modified by callbackHttpGet()
|
||||
mRequestedOffset = cur_size;
|
||||
|
||||
bool res = false;
|
||||
if (!mUrl.empty())
|
||||
@@ -1305,7 +1329,7 @@ bool LLTextureFetchWorker::doWork(S32 param)
|
||||
mLoaded = FALSE;
|
||||
mGetStatus = 0;
|
||||
mGetReason.clear();
|
||||
LL_DEBUGS("Texture") << "HTTP GET: " << mID << " Offset: " << offset
|
||||
LL_DEBUGS("Texture") << "HTTP GET: " << mID << " Offset: " << mRequestedOffset
|
||||
<< " Bytes: " << mRequestedSize
|
||||
<< " Bandwidth(kbps): " << mFetcher->getTextureBandwidth() << "/" << mFetcher->mMaxBandwidth
|
||||
<< LL_ENDL;
|
||||
@@ -1323,12 +1347,27 @@ bool LLTextureFetchWorker::doWork(S32 param)
|
||||
LLImageBase::TYPE_AVATAR_BAKE == mType);
|
||||
#endif
|
||||
|
||||
if(mRequestedOffset>0)
|
||||
{
|
||||
// Texture fetching often issues 'speculative' loads that
|
||||
// start beyond the end of the actual asset. Some cache/web
|
||||
// systems, e.g. Varnish, will respond to this not with a
|
||||
// 416 but with a 200 and the entire asset in the response
|
||||
// body. By ensuring that we always have a partially
|
||||
// satisfiable Range request, we avoid that hit to the network.
|
||||
// We just have to deal with the overlapping data which is made
|
||||
// somewhat harder by the fact that grid services don't necessarily
|
||||
// return the Content-Range header on 206 responses. *Sigh*
|
||||
mRequestedSize++;
|
||||
mRequestedOffset--;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
// Will call callbackHttpGet when curl request completes
|
||||
AIHTTPHeaders headers("Accept", "image/x-j2c");
|
||||
LLHTTPClient::getByteRange(mUrl, offset, mRequestedSize,
|
||||
new HTTPGetResponder(mFetcher, mID, LLTimer::getTotalTime(), mRequestedSize, offset, true), headers);
|
||||
LLHTTPClient::getByteRange(mUrl, mRequestedOffset, mRequestedSize,
|
||||
new HTTPGetResponder(mFetcher, mID, LLTimer::getTotalTime(), mRequestedSize, mRequestedOffset, true), headers);
|
||||
res = true;
|
||||
}
|
||||
catch(AICurlNoEasyHandle const& error)
|
||||
@@ -1441,18 +1480,37 @@ bool LLTextureFetchWorker::doWork(S32 param)
|
||||
return false; // retry
|
||||
}
|
||||
}
|
||||
|
||||
llassert_always(mBufferSize == cur_size + mRequestedSize);
|
||||
if(!mBufferSize)//no data received.
|
||||
{
|
||||
FREE_MEM(LLImageBase::getPrivatePool(), mBuffer);
|
||||
mBuffer = NULL;
|
||||
|
||||
if(mHttpBuffer.empty())//no data received.
|
||||
{
|
||||
//abort.
|
||||
mState = DONE;
|
||||
return true;
|
||||
}
|
||||
|
||||
S32 total_size(cur_size + mRequestedSize);
|
||||
S32 src_offset(0);
|
||||
|
||||
if(mRequestedOffset && mRequestedOffset != cur_size)
|
||||
{
|
||||
// In case of a partial response, our offset may
|
||||
// not be trivially contiguous with the data we have.
|
||||
// Get back into alignment.
|
||||
if (mRequestedOffset > cur_size)
|
||||
{
|
||||
LL_WARNS("Texture") << "Partial HTTP response produces break in image data for texture "
|
||||
<< mID << ". Aborting load." << LL_ENDL;
|
||||
mState = DONE;
|
||||
return true;
|
||||
}
|
||||
src_offset = cur_size - mRequestedOffset;
|
||||
total_size -= src_offset;
|
||||
mRequestedSize -= src_offset; // Make requested values reflect useful part
|
||||
mRequestedOffset += src_offset;
|
||||
|
||||
}
|
||||
llassert(total_size == cur_size + mRequestedSize);
|
||||
|
||||
if (mFormattedImage.isNull())
|
||||
{
|
||||
// For now, create formatted image based on extension
|
||||
@@ -1466,25 +1524,26 @@ bool LLTextureFetchWorker::doWork(S32 param)
|
||||
|
||||
if (mHaveAllData && mRequestedDiscard == 0) //the image file is fully loaded.
|
||||
{
|
||||
mFileSize = mBufferSize;
|
||||
mFileSize = total_size;
|
||||
}
|
||||
else //the file size is unknown.
|
||||
{
|
||||
mFileSize = mBufferSize + 1 ; //flag the file is not fully loaded.
|
||||
mFileSize = total_size + 1 ; //flag the file is not fully loaded.
|
||||
}
|
||||
|
||||
U8* buffer = (U8*)ALLOCATE_MEM(LLImageBase::getPrivatePool(), mBufferSize);
|
||||
U8* buffer = (U8*)ALLOCATE_MEM(LLImageBase::getPrivatePool(), total_size);
|
||||
if (cur_size > 0)
|
||||
{
|
||||
memcpy(buffer, mFormattedImage->getData(), cur_size);
|
||||
}
|
||||
memcpy(buffer + cur_size, mBuffer, mRequestedSize); // append
|
||||
if (mRequestedSize > 0)
|
||||
{
|
||||
memcpy(buffer + mRequestedOffset, &mHttpBuffer[src_offset], mRequestedSize); // append
|
||||
}
|
||||
// NOTE: setData releases current data and owns new data (buffer)
|
||||
mFormattedImage->setData(buffer, mBufferSize);
|
||||
mFormattedImage->setData(buffer, total_size);
|
||||
// delete temp data
|
||||
FREE_MEM(LLImageBase::getPrivatePool(), mBuffer); // Note: not 'buffer' (assigned in setData())
|
||||
mBuffer = NULL;
|
||||
mBufferSize = 0;
|
||||
std::vector<U8>().swap(mHttpBuffer);
|
||||
mLoadedDiscard = mRequestedDiscard;
|
||||
mState = DECODE_IMAGE;
|
||||
if(mWriteToCacheState != NOT_WRITE)
|
||||
@@ -1838,9 +1897,9 @@ S32 LLTextureFetchWorker::callbackHttpGet(const LLChannelDescriptors& channels,
|
||||
if (data_size > 0)
|
||||
{
|
||||
// *TODO: set the formatted image data here directly to avoid the copy
|
||||
mBuffer = (U8*)ALLOCATE_MEM(LLImageBase::getPrivatePool(), data_size);
|
||||
buffer->readAfter(channels.in(), NULL, mBuffer, data_size);
|
||||
mBufferSize += data_size;
|
||||
llassert(mHttpBuffer.empty());
|
||||
mHttpBuffer.resize(data_size);
|
||||
buffer->readAfter(channels.in(), NULL, &mHttpBuffer[0], data_size);
|
||||
if (data_size < mRequestedSize && mRequestedDiscard == 0)
|
||||
{
|
||||
mHaveAllData = TRUE;
|
||||
@@ -1852,7 +1911,6 @@ S32 LLTextureFetchWorker::callbackHttpGet(const LLChannelDescriptors& channels,
|
||||
mHaveAllData = TRUE;
|
||||
llassert_always(mDecodeHandle == 0);
|
||||
mFormattedImage = NULL; // discard any previous data we had
|
||||
mBufferSize = data_size;
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -1861,7 +1919,7 @@ S32 LLTextureFetchWorker::callbackHttpGet(const LLChannelDescriptors& channels,
|
||||
// so presumably we have all of it
|
||||
mHaveAllData = TRUE;
|
||||
}
|
||||
mRequestedSize = data_size;
|
||||
mRequestedSize = llmin(data_size, mRequestedSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -2112,7 +2170,7 @@ bool LLTextureFetch::createRequest(const std::string& url, const LLUUID& id, con
|
||||
worker->unlockWorkMutex();
|
||||
}
|
||||
|
||||
llinfos << "REQUESTED: " << id << " Discard: " << desired_discard << llendl;
|
||||
//llinfos << "REQUESTED: " << id << " Discard: " << desired_discard << llendl;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user