summaryrefslogtreecommitdiff
path: root/indra/llmessage
diff options
context:
space:
mode:
Diffstat (limited to 'indra/llmessage')
-rw-r--r--indra/llmessage/llavatarnamecache.cpp78
-rw-r--r--indra/llmessage/llavatarnamecache.h4
-rw-r--r--indra/llmessage/llcurl.cpp223
-rw-r--r--indra/llmessage/llcurl.h65
-rw-r--r--indra/llmessage/llhttpassetstorage.cpp2
5 files changed, 322 insertions, 50 deletions
diff --git a/indra/llmessage/llavatarnamecache.cpp b/indra/llmessage/llavatarnamecache.cpp
index ff31f7665e..700525e1fa 100644
--- a/indra/llmessage/llavatarnamecache.cpp
+++ b/indra/llmessage/llavatarnamecache.cpp
@@ -87,6 +87,9 @@ namespace LLAvatarNameCache
/// Time when unrefreshed cached names were checked last
static F64 sLastExpireCheck;
+ /// Time-to-live for a temp cache entry.
+ const F64 TEMP_CACHE_ENTRY_LIFETIME = 60.0;
+
//-----------------------------------------------------------------------
// Internal methods
//-----------------------------------------------------------------------
@@ -274,7 +277,7 @@ void LLAvatarNameCache::handleAgentError(const LLUUID& agent_id)
{
// there is no existing cache entry, so make a temporary name from legacy
LL_WARNS("AvNameCache") << "LLAvatarNameCache get legacy for agent "
- << agent_id << LL_ENDL;
+ << agent_id << LL_ENDL;
gCacheName->get(agent_id, false, // legacy compatibility
boost::bind(&LLAvatarNameCache::legacyNameCallback,
_1, _2, _3));
@@ -287,13 +290,14 @@ void LLAvatarNameCache::handleAgentError(const LLUUID& agent_id)
// Clear this agent from the pending list
LLAvatarNameCache::sPendingQueue.erase(agent_id);
- const LLAvatarName& av_name = existing->second;
+ LLAvatarName& av_name = existing->second;
LL_DEBUGS("AvNameCache") << "LLAvatarNameCache use cache for agent "
<< agent_id
<< "user '" << av_name.mUsername << "' "
<< "display '" << av_name.mDisplayName << "' "
<< "expires in " << av_name.mExpires - LLFrameTimer::getTotalSeconds() << " seconds"
<< LL_ENDL;
+ av_name.mExpires = LLFrameTimer::getTotalSeconds() + TEMP_CACHE_ENTRY_LIFETIME; // reset expiry time so we don't constantly rerequest.
}
}
@@ -330,8 +334,9 @@ void LLAvatarNameCache::requestNamesViaCapability()
// http://pdp60.lindenlab.com:8000/agents/?ids=3941037e-78ab-45f0-b421-bd6e77c1804d&ids=0012809d-7d2d-4c24-9609-af1230a37715&ids=0019aaba-24af-4f0a-aa72-6457953cf7f0
//
// Apache can handle URLs of 4096 chars, but let's be conservative
- const U32 NAME_URL_MAX = 4096;
- const U32 NAME_URL_SEND_THRESHOLD = 3000;
+ static const U32 NAME_URL_MAX = 4096;
+ static const U32 NAME_URL_SEND_THRESHOLD = 3500;
+
std::string url;
url.reserve(NAME_URL_MAX);
@@ -339,10 +344,12 @@ void LLAvatarNameCache::requestNamesViaCapability()
agent_ids.reserve(128);
U32 ids = 0;
- ask_queue_t::const_iterator it = sAskQueue.begin();
- for ( ; it != sAskQueue.end(); ++it)
+ ask_queue_t::const_iterator it;
+ while(!sAskQueue.empty())
{
+ it = sAskQueue.begin();
const LLUUID& agent_id = *it;
+ sAskQueue.erase(it);
if (url.empty())
{
@@ -365,27 +372,17 @@ void LLAvatarNameCache::requestNamesViaCapability()
if (url.size() > NAME_URL_SEND_THRESHOLD)
{
- LL_DEBUGS("AvNameCache") << "LLAvatarNameCache::requestNamesViaCapability first "
- << ids << " ids"
- << LL_ENDL;
- LLHTTPClient::get(url, new LLAvatarNameResponder(agent_ids));
- url.clear();
- agent_ids.clear();
+ break;
}
}
if (!url.empty())
{
- LL_DEBUGS("AvNameCache") << "LLAvatarNameCache::requestNamesViaCapability all "
+ LL_DEBUGS("AvNameCache") << "LLAvatarNameCache::requestNamesViaCapability requested "
<< ids << " ids"
<< LL_ENDL;
LLHTTPClient::get(url, new LLAvatarNameResponder(agent_ids));
- url.clear();
- agent_ids.clear();
}
-
- // We've moved all asks to the pending request queue
- sAskQueue.clear();
}
void LLAvatarNameCache::legacyNameCallback(const LLUUID& agent_id,
@@ -402,20 +399,25 @@ void LLAvatarNameCache::legacyNameCallback(const LLUUID& agent_id,
<< LL_ENDL;
buildLegacyName(full_name, &av_name);
- // Don't add to cache, the data already exists in the legacy name system
- // cache and we don't want or need duplicate storage, because keeping the
- // two copies in sync is complex.
- processName(agent_id, av_name, false);
+ // Add to cache, because if we don't we'll keep rerequesting the
+ // same record forever. buildLegacyName should always guarantee
+ // that these records expire reasonably soon
+ // (in TEMP_CACHE_ENTRY_LIFETIME seconds), so if the failure was due
+ // to something temporary we will eventually request and get the right data.
+ processName(agent_id, av_name, true);
}
void LLAvatarNameCache::requestNamesViaLegacy()
{
+ static const S32 MAX_REQUESTS = 100;
F64 now = LLFrameTimer::getTotalSeconds();
std::string full_name;
- ask_queue_t::const_iterator it = sAskQueue.begin();
- for (; it != sAskQueue.end(); ++it)
+ ask_queue_t::const_iterator it;
+ for (S32 requests = 0; !sAskQueue.empty() && requests < MAX_REQUESTS; ++requests)
{
+ it = sAskQueue.begin();
const LLUUID& agent_id = *it;
+ sAskQueue.erase(it);
// Mark as pending first, just in case the callback is immediately
// invoked below. This should never happen in practice.
@@ -427,10 +429,6 @@ void LLAvatarNameCache::requestNamesViaLegacy()
boost::bind(&LLAvatarNameCache::legacyNameCallback,
_1, _2, _3));
}
-
- // We've either answered immediately or moved all asks to the
- // pending queue
- sAskQueue.clear();
}
void LLAvatarNameCache::initClass(bool running)
@@ -507,11 +505,11 @@ void LLAvatarNameCache::idle()
// *TODO: Possibly re-enabled this based on People API load measurements
// 100 ms is the threshold for "user speed" operations, so we can
// stall for about that long to batch up requests.
- //const F32 SECS_BETWEEN_REQUESTS = 0.1f;
- //if (!sRequestTimer.checkExpirationAndReset(SECS_BETWEEN_REQUESTS))
- //{
- // return;
- //}
+ const F32 SECS_BETWEEN_REQUESTS = 0.1f;
+ if (!sRequestTimer.hasExpired())
+ {
+ return;
+ }
if (!sAskQueue.empty())
{
@@ -526,6 +524,12 @@ void LLAvatarNameCache::idle()
}
}
+ if (sAskQueue.empty())
+ {
+ // cleared the list, reset the request timer.
+ sRequestTimer.resetWithExpiry(SECS_BETWEEN_REQUESTS);
+ }
+
// erase anything that has not been refreshed for more than MAX_UNREFRESHED_TIME
eraseUnrefreshed();
}
@@ -583,7 +587,7 @@ void LLAvatarNameCache::buildLegacyName(const std::string& full_name,
av_name->mDisplayName = full_name;
av_name->mIsDisplayNameDefault = true;
av_name->mIsTemporaryName = true;
- av_name->mExpires = F64_MAX; // not used because these are not cached
+ av_name->mExpires = LLFrameTimer::getTotalSeconds() + TEMP_CACHE_ENTRY_LIFETIME;
LL_DEBUGS("AvNameCache") << "LLAvatarNameCache::buildLegacyName "
<< full_name
<< LL_ENDL;
@@ -737,12 +741,6 @@ void LLAvatarNameCache::erase(const LLUUID& agent_id)
sCache.erase(agent_id);
}
-void LLAvatarNameCache::fetch(const LLUUID& agent_id)
-{
- // re-request, even if request is already pending
- sAskQueue.insert(agent_id);
-}
-
void LLAvatarNameCache::insert(const LLUUID& agent_id, const LLAvatarName& av_name)
{
// *TODO: update timestamp if zero?
diff --git a/indra/llmessage/llavatarnamecache.h b/indra/llmessage/llavatarnamecache.h
index 064942fe53..79f170f7c8 100644
--- a/indra/llmessage/llavatarnamecache.h
+++ b/indra/llmessage/llavatarnamecache.h
@@ -86,10 +86,6 @@ namespace LLAvatarNameCache
/// Provide some fallback for agents that return errors
void handleAgentError(const LLUUID& agent_id);
- // Force a re-fetch of the most recent data, but keep the current
- // data in cache
- void fetch(const LLUUID& agent_id);
-
void insert(const LLUUID& agent_id, const LLAvatarName& av_name);
// Compute name expiration time from HTTP Cache-Control header,
diff --git a/indra/llmessage/llcurl.cpp b/indra/llmessage/llcurl.cpp
index 10c83e6572..8ffa8e4271 100644
--- a/indra/llmessage/llcurl.cpp
+++ b/indra/llmessage/llcurl.cpp
@@ -294,6 +294,8 @@ LLCurl::Easy* LLCurl::Easy::getEasy()
// multi handles cache if they are added to one.
CURLcode result = curl_easy_setopt(easy->mCurlEasyHandle, CURLOPT_DNS_CACHE_TIMEOUT, 0);
check_curl_code(result);
+ result = curl_easy_setopt(easy->mCurlEasyHandle, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
+ check_curl_code(result);
++gCurlEasyCount;
return easy;
@@ -482,7 +484,8 @@ void LLCurl::Easy::prepRequest(const std::string& url,
//setopt(CURLOPT_VERBOSE, 1); // useful for debugging
setopt(CURLOPT_NOSIGNAL, 1);
-
+ setopt(CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
+
// Set the CURL options for either Socks or HTTP proxy
LLProxy::getInstance()->applyProxySettings(this);
@@ -938,8 +941,8 @@ bool LLCurlThread::CurlRequest::processRequest()
if(!completed)
{
- setPriority(LLQueuedThread::PRIORITY_LOW) ;
- }
+ setPriority(LLQueuedThread::PRIORITY_LOW) ;
+ }
}
return completed ;
@@ -949,7 +952,7 @@ void LLCurlThread::CurlRequest::finishRequest(bool completed)
{
if(mMulti->isDead())
{
- mCurlThread->deleteMulti(mMulti) ;
+ mCurlThread->deleteMulti(mMulti) ;
}
else
{
@@ -993,6 +996,7 @@ void LLCurlThread::killMulti(LLCurl::Multi* multi)
return ;
}
+
multi->markDead() ;
}
@@ -1098,7 +1102,9 @@ void LLCurlRequest::get(const std::string& url, LLCurl::ResponderPtr responder)
{
getByteRange(url, headers_t(), 0, -1, responder);
}
-
+
+// Note: (length==0) is interpreted as "the rest of the file", i.e. the whole file if (offset==0) or
+// the remainder of the file if not.
bool LLCurlRequest::getByteRange(const std::string& url,
const headers_t& headers,
S32 offset, S32 length,
@@ -1117,6 +1123,11 @@ bool LLCurlRequest::getByteRange(const std::string& url,
std::string range = llformat("Range: bytes=%d-%d", offset,offset+length-1);
easy->slist_append(range.c_str());
}
+ else if (offset > 0)
+ {
+ std::string range = llformat("Range: bytes=%d-", offset);
+ easy->slist_append(range.c_str());
+ }
easy->setHeaders();
bool res = addEasy(easy);
return res;
@@ -1244,6 +1255,208 @@ S32 LLCurlRequest::getQueued()
return queued;
}
+LLCurlTextureRequest::LLCurlTextureRequest(S32 concurrency) :
+ LLCurlRequest(),
+ mConcurrency(concurrency),
+ mInQueue(0),
+ mMutex(NULL),
+ mHandleCounter(1),
+ mTotalIssuedRequests(0),
+ mTotalReceivedBits(0)
+{
+ mGlobalTimer.reset();
+}
+
+LLCurlTextureRequest::~LLCurlTextureRequest()
+{
+ mRequestMap.clear();
+
+ for(req_queue_t::iterator iter = mCachedRequests.begin(); iter != mCachedRequests.end(); ++iter)
+ {
+ delete *iter;
+ }
+ mCachedRequests.clear();
+}
+
+//return 0: success
+// > 0: cached handle
+U32 LLCurlTextureRequest::getByteRange(const std::string& url,
+ const headers_t& headers,
+ S32 offset, S32 length, U32 pri,
+ LLCurl::ResponderPtr responder, F32 delay_time)
+{
+ U32 ret_val = 0;
+ bool success = false;
+
+ if(mInQueue < mConcurrency && delay_time < 0.f)
+ {
+ success = LLCurlRequest::getByteRange(url, headers, offset, length, responder);
+ }
+
+ LLMutexLock lock(&mMutex);
+
+ if(success)
+ {
+ mInQueue++;
+ mTotalIssuedRequests++;
+ }
+ else
+ {
+ request_t* request = new request_t(mHandleCounter, url, headers, offset, length, pri, responder);
+ if(delay_time > 0.f)
+ {
+ request->mStartTime = mGlobalTimer.getElapsedTimeF32() + delay_time;
+ }
+
+ mCachedRequests.insert(request);
+ mRequestMap[mHandleCounter] = request;
+ ret_val = mHandleCounter;
+ mHandleCounter++;
+
+ if(!mHandleCounter)
+ {
+ mHandleCounter = 1;
+ }
+ }
+
+ return ret_val;
+}
+
+void LLCurlTextureRequest::completeRequest(S32 received_bytes)
+{
+ LLMutexLock lock(&mMutex);
+
+ llassert_always(mInQueue > 0);
+
+ mInQueue--;
+ mTotalReceivedBits += received_bytes * 8;
+}
+
+void LLCurlTextureRequest::nextRequests()
+{
+ if(mCachedRequests.empty() || mInQueue >= mConcurrency)
+ {
+ return;
+ }
+
+ F32 cur_time = mGlobalTimer.getElapsedTimeF32();
+
+ req_queue_t::iterator iter;
+ {
+ LLMutexLock lock(&mMutex);
+ iter = mCachedRequests.begin();
+ }
+ while(1)
+ {
+ request_t* request = *iter;
+ if(request->mStartTime < cur_time)
+ {
+ if(!LLCurlRequest::getByteRange(request->mUrl, request->mHeaders, request->mOffset, request->mLength, request->mResponder))
+ {
+ break;
+ }
+
+ LLMutexLock lock(&mMutex);
+ ++iter;
+ mInQueue++;
+ mTotalIssuedRequests++;
+ mCachedRequests.erase(request);
+ mRequestMap.erase(request->mHandle);
+ delete request;
+
+ if(iter == mCachedRequests.end() || mInQueue >= mConcurrency)
+ {
+ break;
+ }
+ }
+ else
+ {
+ LLMutexLock lock(&mMutex);
+ ++iter;
+ if(iter == mCachedRequests.end() || mInQueue >= mConcurrency)
+ {
+ break;
+ }
+ }
+ }
+
+ return;
+}
+
+void LLCurlTextureRequest::updatePriority(U32 handle, U32 pri)
+{
+ if(!handle)
+ {
+ return;
+ }
+
+ LLMutexLock lock(&mMutex);
+
+ std::map<S32, request_t*>::iterator iter = mRequestMap.find(handle);
+ if(iter != mRequestMap.end())
+ {
+ request_t* req = iter->second;
+
+ if(req->mPriority != pri)
+ {
+ mCachedRequests.erase(req);
+ req->mPriority = pri;
+ mCachedRequests.insert(req);
+ }
+ }
+}
+
+void LLCurlTextureRequest::removeRequest(U32 handle)
+{
+ if(!handle)
+ {
+ return;
+ }
+
+ LLMutexLock lock(&mMutex);
+
+ std::map<S32, request_t*>::iterator iter = mRequestMap.find(handle);
+ if(iter != mRequestMap.end())
+ {
+ request_t* req = iter->second;
+ mRequestMap.erase(iter);
+ mCachedRequests.erase(req);
+ delete req;
+ }
+}
+
+bool LLCurlTextureRequest::isWaiting(U32 handle)
+{
+ if(!handle)
+ {
+ return false;
+ }
+
+ LLMutexLock lock(&mMutex);
+ return mRequestMap.find(handle) != mRequestMap.end();
+}
+
+U32 LLCurlTextureRequest::getTotalReceivedBits()
+{
+ LLMutexLock lock(&mMutex);
+
+ U32 bits = mTotalReceivedBits;
+ mTotalReceivedBits = 0;
+ return bits;
+}
+
+U32 LLCurlTextureRequest::getTotalIssuedRequests()
+{
+ LLMutexLock lock(&mMutex);
+ return mTotalIssuedRequests;
+}
+
+S32 LLCurlTextureRequest::getNumRequests()
+{
+ LLMutexLock lock(&mMutex);
+ return mInQueue;
+}
+
////////////////////////////////////////////////////////////////////////////
// For generating one easy request
// associated with a single multi request
diff --git a/indra/llmessage/llcurl.h b/indra/llmessage/llcurl.h
index 62947bdb9d..7bcf61e233 100644
--- a/indra/llmessage/llcurl.h
+++ b/indra/llmessage/llcurl.h
@@ -407,6 +407,71 @@ private:
BOOL mProcessing;
};
+//for texture fetch only
+class LLCurlTextureRequest : public LLCurlRequest
+{
+public:
+ LLCurlTextureRequest(S32 concurrency);
+ ~LLCurlTextureRequest();
+
+ U32 getByteRange(const std::string& url, const headers_t& headers, S32 offset, S32 length, U32 pri, LLCurl::ResponderPtr responder, F32 delay_time = -1.f);
+ void nextRequests();
+ void completeRequest(S32 received_bytes);
+
+ void updatePriority(U32 handle, U32 pri);
+ void removeRequest(U32 handle);
+
+ U32 getTotalReceivedBits();
+ U32 getTotalIssuedRequests();
+ S32 getNumRequests();
+ bool isWaiting(U32 handle);
+
+private:
+ LLMutex mMutex;
+ S32 mConcurrency;
+ S32 mInQueue; //request currently in queue.
+ U32 mHandleCounter;
+ U32 mTotalIssuedRequests;
+ U32 mTotalReceivedBits;
+
+ typedef struct _request_t
+ {
+ _request_t(U32 handle, const std::string& url, const headers_t& headers, S32 offset, S32 length, U32 pri, LLCurl::ResponderPtr responder) :
+ mHandle(handle), mUrl(url), mHeaders(headers), mOffset(offset), mLength(length), mPriority(pri), mResponder(responder), mStartTime(0.f)
+ {}
+
+ U32 mHandle;
+ std::string mUrl;
+ LLCurlRequest::headers_t mHeaders;
+ S32 mOffset;
+ S32 mLength;
+ LLCurl::ResponderPtr mResponder;
+ U32 mPriority;
+ F32 mStartTime; //start time to issue this request
+ } request_t;
+
+ struct request_compare
+ {
+ bool operator()(const request_t* lhs, const request_t* rhs) const
+ {
+ if(lhs->mPriority != rhs->mPriority)
+ {
+ return lhs->mPriority > rhs->mPriority; // higher priority in front of queue (set)
+ }
+ else
+ {
+ return (U32)lhs < (U32)rhs;
+ }
+ }
+ };
+
+ typedef std::set<request_t*, request_compare> req_queue_t;
+ req_queue_t mCachedRequests;
+ std::map<S32, request_t*> mRequestMap;
+
+ LLFrameTimer mGlobalTimer;
+};
+
class LLCurlEasyRequest
{
public:
diff --git a/indra/llmessage/llhttpassetstorage.cpp b/indra/llmessage/llhttpassetstorage.cpp
index 612d765969..d6ed08055e 100644
--- a/indra/llmessage/llhttpassetstorage.cpp
+++ b/indra/llmessage/llhttpassetstorage.cpp
@@ -749,7 +749,7 @@ LLAssetRequest* LLHTTPAssetStorage::findNextRequest(LLAssetStorage::request_list
request_list_t::iterator pending_iter = pending.begin();
request_list_t::iterator pending_end = pending.end();
// Loop over all pending requests until we miss finding it in the running list.
- for (; pending_iter != pending.end(); ++pending_iter)
+ for (; pending_iter != pending_end; ++pending_iter)
{
LLAssetRequest* req = *pending_iter;
// Look for this pending request in the running list.