From ffcbbf4aaabc652c2050ca6147a9388217cfcaa7 Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Thu, 11 Feb 2010 18:00:00 -0600 Subject: Multi-threaded asset uploading with proper ordering first draft. --- indra/llmessage/llcurl.cpp | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) (limited to 'indra/llmessage/llcurl.cpp') diff --git a/indra/llmessage/llcurl.cpp b/indra/llmessage/llcurl.cpp index 024e17a777..b93b94cd25 100644 --- a/indra/llmessage/llcurl.cpp +++ b/indra/llmessage/llcurl.cpp @@ -55,6 +55,7 @@ #include "llstl.h" #include "llsdserialize.h" #include "llthread.h" +#include "llvfile.h" ////////////////////////////////////////////////////////////////////////////// /* @@ -801,7 +802,34 @@ bool LLCurlRequest::post(const std::string& url, bool res = addEasy(easy); return res; } + +bool LLCurlRequest::post(const std::string& url, + const headers_t& headers, + const std::string& data, + LLCurl::ResponderPtr responder) +{ + LLCurl::Easy* easy = allocEasy(); + if (!easy) + { + return false; + } + easy->prepRequest(url, headers, responder); + + easy->getInput().write(data.data(), data.size()); + S32 bytes = easy->getInput().str().length(); + easy->setopt(CURLOPT_POST, 1); + easy->setopt(CURLOPT_POSTFIELDS, (void*)NULL); + easy->setopt(CURLOPT_POSTFIELDSIZE, bytes); + + easy->slist_append("Content-Type: application/octet-stream"); + easy->setHeaders(); + + lldebugs << "POSTING: " << bytes << " bytes." << llendl; + bool res = addEasy(easy); + return res; +} + // Note: call once per frame S32 LLCurlRequest::process() { -- cgit v1.2.3 From de88d6ced487fd55fa6f6bb860849979f031a363 Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Wed, 17 Feb 2010 11:29:16 -0600 Subject: Switched program database on windows to edit and continue for non-release builds. Adding a debug watch to LLCurlRequest to avoid invalidating iterator on processing posts. Mesh bulk uploading rewrite work in progress. 404 icons for mesh assets. --- indra/llmessage/llcurl.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'indra/llmessage/llcurl.cpp') diff --git a/indra/llmessage/llcurl.cpp b/indra/llmessage/llcurl.cpp index b93b94cd25..5212ba1eca 100644 --- a/indra/llmessage/llcurl.cpp +++ b/indra/llmessage/llcurl.cpp @@ -711,6 +711,7 @@ LLCurlRequest::LLCurlRequest() : mActiveRequestCount(0) { mThreadID = LLThread::currentID(); + mProcessing = FALSE; } LLCurlRequest::~LLCurlRequest() @@ -745,6 +746,11 @@ LLCurl::Easy* LLCurlRequest::allocEasy() bool LLCurlRequest::addEasy(LLCurl::Easy* easy) { llassert_always(mActiveMulti); + + if (mProcessing) + { + llerrs << "Posting to a LLCurlRequest instance from within a responder is not allowed (causes DNS timeouts)." << llendl; + } bool res = mActiveMulti->addEasy(easy); return res; } @@ -835,6 +841,8 @@ S32 LLCurlRequest::process() { llassert_always(mThreadID == LLThread::currentID()); S32 res = 0; + + mProcessing = TRUE; for (curlmulti_set_t::iterator iter = mMultiSet.begin(); iter != mMultiSet.end(); ) { @@ -848,6 +856,7 @@ S32 LLCurlRequest::process() delete multi; } } + mProcessing = FALSE; return res; } -- cgit v1.2.3 From 74621ff8a8a141d50a3c92430afbe53a9e00edb5 Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Wed, 17 Feb 2010 15:50:50 -0600 Subject: Post-review cleanup. --- indra/llmessage/llcurl.cpp | 1 - 1 file changed, 1 deletion(-) (limited to 'indra/llmessage/llcurl.cpp') diff --git a/indra/llmessage/llcurl.cpp b/indra/llmessage/llcurl.cpp index 5212ba1eca..0c919011ac 100644 --- a/indra/llmessage/llcurl.cpp +++ b/indra/llmessage/llcurl.cpp @@ -55,7 +55,6 @@ #include "llstl.h" #include "llsdserialize.h" #include "llthread.h" -#include "llvfile.h" ////////////////////////////////////////////////////////////////////////////// /* -- cgit v1.2.3 From 4de18937025f92a0340277c3215fc43cac2f6688 Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Wed, 24 Feb 2010 19:53:22 -0600 Subject: Added lower level pool to curl easy handles to speed up HTTP requests (from 40 ms per request to < 1 ms per request). --- indra/llmessage/llcurl.cpp | 87 ++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 84 insertions(+), 3 deletions(-) (limited to 'indra/llmessage/llcurl.cpp') diff --git a/indra/llmessage/llcurl.cpp b/indra/llmessage/llcurl.cpp index 0c919011ac..c640e176ee 100644 --- a/indra/llmessage/llcurl.cpp +++ b/indra/llmessage/llcurl.cpp @@ -55,6 +55,7 @@ #include "llstl.h" #include "llsdserialize.h" #include "llthread.h" +#include "lltimer.h" ////////////////////////////////////////////////////////////////////////////// /* @@ -256,7 +257,12 @@ public: void resetState(); + static CURL* allocEasyHandle(); + static void releaseEasyHandle(CURL* handle); + private: + friend class LLCurl; + CURL* mCurlEasyHandle; struct curl_slist* mHeaders; @@ -271,8 +277,62 @@ private: std::vector mStrings; ResponderPtr mResponder; + + static std::set sFreeHandles; + static std::set sActiveHandles; + static LLMutex* sHandleMutex; }; +std::set LLCurl::Easy::sFreeHandles; +std::set LLCurl::Easy::sActiveHandles; +LLMutex* LLCurl::Easy::sHandleMutex = NULL; + + +//static +CURL* LLCurl::Easy::allocEasyHandle() +{ + CURL* ret = NULL; + LLMutexLock lock(sHandleMutex); + if (sFreeHandles.empty()) + { + ret = curl_easy_init(); + } + else + { + ret = *(sFreeHandles.begin()); + sFreeHandles.erase(ret); + curl_easy_reset(ret); + } + + if (ret) + { + sActiveHandles.insert(ret); + } + + return ret; +} + +//static +void LLCurl::Easy::releaseEasyHandle(CURL* handle) +{ + if (!handle) + { + llerrs << "handle cannot be NULL!" << llendl; + } + + LLMutexLock lock(sHandleMutex); + + if (sActiveHandles.find(handle) != sActiveHandles.end()) + { + sActiveHandles.erase(handle); + sFreeHandles.insert(handle); + } + else + { + llerrs << "Invalid handle." << llendl; + } +} + LLCurl::Easy::Easy() : mHeaders(NULL), mCurlEasyHandle(NULL) @@ -283,11 +343,12 @@ LLCurl::Easy::Easy() LLCurl::Easy* LLCurl::Easy::getEasy() { Easy* easy = new Easy(); - easy->mCurlEasyHandle = curl_easy_init(); + easy->mCurlEasyHandle = allocEasyHandle(); + if (!easy->mCurlEasyHandle) { // this can happen if we have too many open files (fails in c-ares/ares_init.c) - llwarns << "curl_multi_init() returned NULL! Easy handles: " << gCurlEasyCount << " Multi handles: " << gCurlMultiCount << llendl; + llwarns << "allocEasyHandle() returned NULL! Easy handles: " << gCurlEasyCount << " Multi handles: " << gCurlMultiCount << llendl; delete easy; return NULL; } @@ -301,7 +362,7 @@ LLCurl::Easy* LLCurl::Easy::getEasy() LLCurl::Easy::~Easy() { - curl_easy_cleanup(mCurlEasyHandle); + releaseEasyHandle(mCurlEasyHandle); --gCurlEasyCount; curl_slist_free_all(mHeaders); for_each(mStrings.begin(), mStrings.end(), DeletePointerArray()); @@ -543,6 +604,7 @@ LLCurl::Multi::Multi() mErrorCount(0) { mCurlMultiHandle = curl_multi_init(); + if (!mCurlMultiHandle) { llwarns << "curl_multi_init() returned NULL! Easy handles: " << gCurlEasyCount << " Multi handles: " << gCurlMultiCount << llendl; @@ -1078,6 +1140,8 @@ void LLCurl::initClass() // - http://curl.haxx.se/libcurl/c/curl_global_init.html curl_global_init(CURL_GLOBAL_ALL); + Easy::sHandleMutex = new LLMutex(NULL); + #if SAFE_SSL S32 mutex_count = CRYPTO_num_locks(); for (S32 i=0; i::iterator iter = Easy::sFreeHandles.begin(); iter != Easy::sFreeHandles.end(); ++iter) + { + CURL* curl = *iter; + curl_easy_cleanup(curl); + } + + Easy::sFreeHandles.clear(); + + if (!Easy::sActiveHandles.empty()) + { + llerrs << "CURL easy handles not cleaned up on shutdown!" << llendl; + } + curl_global_cleanup(); } -- cgit v1.2.3 From e9d926385f4d8933d10bb4a3168628e0a6f0ad2a Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Tue, 2 Mar 2010 12:03:00 -0600 Subject: Curl tweaks to get rid of various types of timeouts. - Scrub host names from capability ips (requires disabling SSL host name verification) - Reset connections that have received a timeout (avoids cascading timeouts from reusing a cached bad connection) --- indra/llmessage/llcurl.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'indra/llmessage/llcurl.cpp') diff --git a/indra/llmessage/llcurl.cpp b/indra/llmessage/llcurl.cpp index c640e176ee..637110ba0f 100644 --- a/indra/llmessage/llcurl.cpp +++ b/indra/llmessage/llcurl.cpp @@ -353,9 +353,10 @@ LLCurl::Easy* LLCurl::Easy::getEasy() return NULL; } - // set no DMS caching as default for all easy handles. This prevents them adopting a + // set no DNS caching as default for all easy handles. This prevents them adopting a // multi handles cache if they are added to one. curl_easy_setopt(easy->mCurlEasyHandle, CURLOPT_DNS_CACHE_TIMEOUT, 0); + ++gCurlEasyCount; return easy; } @@ -440,6 +441,7 @@ U32 LLCurl::Easy::report(CURLcode code) { responseCode = 499; responseReason = strerror(code) + " : " + mErrorBuffer; + setopt(CURLOPT_FRESH_CONNECT, TRUE); } if (mResponder) @@ -526,7 +528,7 @@ void LLCurl::Easy::prepRequest(const std::string& url, if (post) setoptString(CURLOPT_ENCODING, ""); -// setopt(CURLOPT_VERBOSE, 1); // usefull for debugging + //setopt(CURLOPT_VERBOSE, 1); // usefull for debugging setopt(CURLOPT_NOSIGNAL, 1); mOutput.reset(new LLBufferArray); @@ -543,9 +545,12 @@ void LLCurl::Easy::prepRequest(const std::string& url, setCA(); setopt(CURLOPT_SSL_VERIFYPEER, LLCurl::getSSLVerify()); - setopt(CURLOPT_SSL_VERIFYHOST, LLCurl::getSSLVerify()? 2 : 0); + //setopt(CURLOPT_SSL_VERIFYHOST, LLCurl::getSSLVerify()? 2 : 0); + setopt(CURLOPT_SSL_VERIFYHOST, 0); setopt(CURLOPT_TIMEOUT, CURL_REQUEST_TIMEOUT); + setopt(CURLOPT_FORBID_REUSE, TRUE); + setoptString(CURLOPT_URL, url); mResponder = responder; -- cgit v1.2.3 From e38adc5baf0bf4090168088fc4b9a71a5b231aa4 Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Tue, 2 Mar 2010 12:35:19 -0600 Subject: cleanup from review --- indra/llmessage/llcurl.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'indra/llmessage/llcurl.cpp') diff --git a/indra/llmessage/llcurl.cpp b/indra/llmessage/llcurl.cpp index 637110ba0f..f8a7eb0417 100644 --- a/indra/llmessage/llcurl.cpp +++ b/indra/llmessage/llcurl.cpp @@ -546,11 +546,11 @@ void LLCurl::Easy::prepRequest(const std::string& url, setopt(CURLOPT_SSL_VERIFYPEER, LLCurl::getSSLVerify()); //setopt(CURLOPT_SSL_VERIFYHOST, LLCurl::getSSLVerify()? 2 : 0); + + //don't verify host name so urls with scrubbed host names will work (improves DNS performance) setopt(CURLOPT_SSL_VERIFYHOST, 0); setopt(CURLOPT_TIMEOUT, CURL_REQUEST_TIMEOUT); - setopt(CURLOPT_FORBID_REUSE, TRUE); - setoptString(CURLOPT_URL, url); mResponder = responder; -- cgit v1.2.3