diff options
author | Monty Brandenberg <monty@lindenlab.com> | 2012-06-01 14:07:34 -0400 |
---|---|---|
committer | Monty Brandenberg <monty@lindenlab.com> | 2012-06-01 14:07:34 -0400 |
commit | b8edacd0bb4feacc3ac1d61421e600c75ab87f7c (patch) | |
tree | 8f0e359445e324e4694e79526e443d5e6c90fab4 | |
parent | 8fc350125c671baeae6b7f8b1814251009f4f50a (diff) |
Major steps towards implementing the policy component.
Identified and reacted to the priority inversion problem we
have in texturefetch. Includes the introduction of a priority_queue
for the requests that are ready. Start some parameterization in
anticipation of having policy_class everywhere. Removed _assert.h
which isn't really needed in indra codebase. Implemented async
setPriority request (which I hope I can get rid of eventually along
with all priorities in this library). Converted to using unsigned
int for priority rather than float. Implemented POST and did
groundwork for PUT.
25 files changed, 869 insertions, 290 deletions
diff --git a/indra/llcorehttp/CMakeLists.txt b/indra/llcorehttp/CMakeLists.txt index ae92fb96fd..85df5364db 100644 --- a/indra/llcorehttp/CMakeLists.txt +++ b/indra/llcorehttp/CMakeLists.txt @@ -23,17 +23,18 @@ include_directories( set(llcorehttp_SOURCE_FILES bufferarray.cpp httpcommon.cpp + httpheaders.cpp + httpoptions.cpp httprequest.cpp httpresponse.cpp - httpoptions.cpp - httpheaders.cpp - _httprequestqueue.cpp + _httplibcurl.cpp + _httpopcancel.cpp _httpoperation.cpp _httpoprequest.cpp - _httpopcancel.cpp - _httpreplyqueue.cpp + _httpopsetpriority.cpp _httppolicy.cpp - _httplibcurl.cpp + _httpreplyqueue.cpp + _httprequestqueue.cpp _httpservice.cpp _refcounted.cpp ) @@ -48,17 +49,19 @@ set(llcorehttp_HEADER_FILES httpoptions.h httprequest.h httpresponse.h + _assert.h + _httplibcurl.h + _httpopcancel.h _httpoperation.h _httpoprequest.h - _httpopcancel.h - _httprequestqueue.h + _httpopsetpriority.h + _httppolicy.h + _httpreadyqueue.h _httpreplyqueue.h + _httprequestqueue.h _httpservice.h - _httppolicy.h - _httplibcurl.h - _assert.h - _refcounted.h _mutex.h + _refcounted.h _thread.h ) diff --git a/indra/llcorehttp/_assert.h b/indra/llcorehttp/_assert.h deleted file mode 100644 index 054f23ef32..0000000000 --- a/indra/llcorehttp/_assert.h +++ /dev/null @@ -1,39 +0,0 @@ -/** - * @file _assert - * @brief assert abstraction - * - * $LicenseInfo:firstyear=2012&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2012, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#ifndef LLCOREINT__ASSERT_H_ -#define LLCOREINT__ASSERT_H_ - -#ifdef DEBUG_ASSERT -#include <cassert> -#define LLINT_ASSERT(x) assert(x) -#else -#define LLINT_ASSERT(x) -#endif - -#endif // LLCOREINT__ASSERT_H_ - - diff --git a/indra/llcorehttp/_httplibcurl.cpp b/indra/llcorehttp/_httplibcurl.cpp index 1b951818e4..704f9baac9 100644 --- a/indra/llcorehttp/_httplibcurl.cpp +++ b/indra/llcorehttp/_httplibcurl.cpp @@ -28,7 +28,6 @@ #include "httpheaders.h" #include "_httpoprequest.h" -#include "_httpservice.h" namespace LLCore @@ -38,6 +37,12 @@ namespace LLCore HttpLibcurl::HttpLibcurl(HttpService * service) : mService(service) { + for (int policy_class(0); policy_class < HttpRequest::POLICY_CLASS_LIMIT; ++policy_class) + { + mMultiHandles[policy_class] = 0; + } + + // Create multi handle for default class mMultiHandles[0] = curl_multi_init(); } @@ -51,15 +56,18 @@ HttpLibcurl::~HttpLibcurl() (*item)->cancel(); (*item)->release(); + mActiveOps.erase(item); } - if (mMultiHandles[0]) + for (int policy_class(0); policy_class < HttpRequest::POLICY_CLASS_LIMIT; ++policy_class) { - // *FIXME: Do some multi cleanup here first - + if (mMultiHandles[policy_class]) + { + // *FIXME: Do some multi cleanup here first - curl_multi_cleanup(mMultiHandles[0]); - mMultiHandles[0] = NULL; + curl_multi_cleanup(mMultiHandles[policy_class]); + mMultiHandles[policy_class] = 0; + } } mService = NULL; @@ -74,31 +82,34 @@ void HttpLibcurl::term() {} -void HttpLibcurl::processTransport() +HttpService::ELoopSpeed HttpLibcurl::processTransport() { - if (mMultiHandles[0]) + // Give libcurl some cycles to do I/O & callbacks + for (int policy_class(0); policy_class < HttpRequest::POLICY_CLASS_LIMIT; ++policy_class) { - // Give libcurl some cycles to do I/O & callbacks + if (! mMultiHandles[policy_class]) + continue; + int running(0); CURLMcode status(CURLM_CALL_MULTI_PERFORM); do { running = 0; - status = curl_multi_perform(mMultiHandles[0], &running); + status = curl_multi_perform(mMultiHandles[policy_class], &running); } while (0 != running && CURLM_CALL_MULTI_PERFORM == status); // Run completion on anything done CURLMsg * msg(NULL); int msgs_in_queue(0); - while ((msg = curl_multi_info_read(mMultiHandles[0], &msgs_in_queue))) + while ((msg = curl_multi_info_read(mMultiHandles[policy_class], &msgs_in_queue))) { if (CURLMSG_DONE == msg->msg) { CURL * handle(msg->easy_handle); CURLcode result(msg->data.result); - completeRequest(mMultiHandles[0], handle, result); + completeRequest(mMultiHandles[policy_class], handle, result); handle = NULL; // No longer valid on return } else if (CURLMSG_NONE == msg->msg) @@ -114,13 +125,18 @@ void HttpLibcurl::processTransport() msgs_in_queue = 0; } } + + return mActiveOps.empty() ? HttpService::REQUEST_SLEEP : HttpService::NORMAL; } void HttpLibcurl::addOp(HttpOpRequest * op) { + llassert_always(op->mReqPolicy < HttpRequest::POLICY_CLASS_LIMIT); + llassert_always(mMultiHandles[op->mReqPolicy] != NULL); + // Create standard handle - if (! op->prepareForGet(mService)) + if (! op->prepareRequest(mService)) { // Couldn't issue request, fail with notification // *FIXME: Need failure path @@ -128,7 +144,7 @@ void HttpLibcurl::addOp(HttpOpRequest * op) } // Make the request live - curl_multi_add_handle(mMultiHandles[0], op->mCurlHandle); + curl_multi_add_handle(mMultiHandles[op->mReqPolicy], op->mCurlHandle); op->mCurlActive = true; // On success, make operation active @@ -190,12 +206,18 @@ void HttpLibcurl::completeRequest(CURLM * multi_handle, CURL * handle, CURLcode } -int HttpLibcurl::activeCount() const +int HttpLibcurl::getActiveCount() const { return mActiveOps.size(); } +int HttpLibcurl::getActiveCountInClass(int /* policy_class */) const +{ + return getActiveCount(); +} + + // --------------------------------------- // Free functions // --------------------------------------- diff --git a/indra/llcorehttp/_httplibcurl.h b/indra/llcorehttp/_httplibcurl.h index 807196628d..ec325c1946 100644 --- a/indra/llcorehttp/_httplibcurl.h +++ b/indra/llcorehttp/_httplibcurl.h @@ -34,18 +34,25 @@ #include <set> +#include "httprequest.h" +#include "_httpservice.h" + namespace LLCore { -class HttpService; class HttpPolicy; class HttpOpRequest; class HttpHeaders; /// Implements libcurl-based transport for an HttpService instance. +/// +/// Threading: Single-threaded. Other than for construction/destruction, +/// all methods are expected to be invoked in a single thread, typically +/// a worker thread of some sort. + class HttpLibcurl { public: @@ -60,12 +67,22 @@ public: static void init(); static void term(); - void processTransport(); - void addOp(HttpOpRequest * op); + /// Give cycles to libcurl to run active requests. Completed + /// operations (successful or failed) will be retried or handed + /// over to the reply queue as final responses. + HttpService::ELoopSpeed processTransport(); - int activeCount() const; + /// Add request to the active list. Caller is expected to have + /// provided us with a reference count to hold the request. (No + /// additional references will be added.) + void addOp(HttpOpRequest * op); + int getActiveCount() const; + int getActiveCountInClass(int policy_class) const; + protected: + /// Invoked when libcurl has indicated a request has been processed + /// to completion and we need to move the request to a new state. void completeRequest(CURLM * multi_handle, CURL * handle, CURLcode status); protected: @@ -74,7 +91,7 @@ protected: protected: HttpService * mService; // Simple reference, not owner active_set_t mActiveOps; - CURLM * mMultiHandles[1]; + CURLM * mMultiHandles[HttpRequest::POLICY_CLASS_LIMIT]; }; // end class HttpLibcurl diff --git a/indra/llcorehttp/_httpopcancel.h b/indra/llcorehttp/_httpopcancel.h index 38ccc585ed..fab6f1f362 100644 --- a/indra/llcorehttp/_httpopcancel.h +++ b/indra/llcorehttp/_httpopcancel.h @@ -45,7 +45,7 @@ namespace LLCore /// HttpOpCancel requests that a previously issued request /// be canceled, if possible. Requests that have been made /// active and are available for sending on the wire cannot -/// be canceled. +/// be canceled. class HttpOpCancel : public HttpOperation { diff --git a/indra/llcorehttp/_httpoperation.cpp b/indra/llcorehttp/_httpoperation.cpp index 17c65b0379..d966efd12b 100644 --- a/indra/llcorehttp/_httpoperation.cpp +++ b/indra/llcorehttp/_httpoperation.cpp @@ -50,7 +50,7 @@ HttpOperation::HttpOperation() mLibraryHandler(NULL), mUserHandler(NULL), mReqPolicy(HttpRequest::DEFAULT_POLICY_ID), - mReqPriority(0.0f) + mReqPriority(0U) { } @@ -95,7 +95,7 @@ void HttpOperation::stageFromRequest(HttpService *) // Default implementation should never be called. This // indicates an operation making a transition that isn't // defined. - LLINT_ASSERT(false); + llassert_always(false); } @@ -105,7 +105,7 @@ void HttpOperation::stageFromReady(HttpService *) // Default implementation should never be called. This // indicates an operation making a transition that isn't // defined. - LLINT_ASSERT(false); + llassert_always(false); } @@ -115,7 +115,7 @@ void HttpOperation::stageFromActive(HttpService *) // Default implementation should never be called. This // indicates an operation making a transition that isn't // defined. - LLINT_ASSERT(false); + llassert_always(false); } diff --git a/indra/llcorehttp/_httpoperation.h b/indra/llcorehttp/_httpoperation.h index 5d06a28586..6c0c3183b7 100644 --- a/indra/llcorehttp/_httpoperation.h +++ b/indra/llcorehttp/_httpoperation.h @@ -44,6 +44,32 @@ class HttpRequest; /// HttpOperation is the base class for all request/reply /// pairs. /// +/// Operations are expected to be of two types: immediate +/// and queued. Immediate requests go to the singleton +/// request queue and when picked up by the worker thread +/// are executed immediately and there results placed on +/// the supplied reply queue. Queued requests (namely for +/// HTTP operations), go to the request queue, are picked +/// up and moved to a ready queue where they're ordered by +/// priority and managed by the policy component, are +/// then activated issuing HTTP requests and moved to an +/// active list managed by the transport (libcurl) component +/// and eventually finalized when a response is available +/// and status and data return via reply queue. +/// +/// To manage these transitions, derived classes implement +/// three methods: stageFromRequest, stageFromReady and +/// stageFromActive. Immediate requests will only override +/// stageFromRequest which will perform the operation and +/// return the result by invoking addAsReply() to put the +/// request on a reply queue. Queued requests will involve +/// all three stage methods. +/// +/// Threading: not thread-safe. Base and derived classes +/// provide no locking. Instances move across threads +/// via queue-like interfaces that are thread compatible +/// and those interfaces establish the access rules. + class HttpOperation : public LLCoreInt::RefCounted { public: @@ -82,7 +108,7 @@ protected: public: unsigned int mReqPolicy; - float mReqPriority; + unsigned int mReqPriority; }; // end class HttpOperation @@ -133,6 +159,20 @@ public: }; // end class HttpOpNull + +/// HttpOpCompare isn't an operation but a uniform comparison +/// functor for STL containers that order by priority. Mainly +/// used for the ready queue container but defined here. +class HttpOpCompare +{ +public: + bool operator()(const HttpOperation * lhs, const HttpOperation * rhs) + { + return lhs->mReqPriority > rhs->mReqPriority; + } +}; // end class HttpOpCompare + + } // end namespace LLCore #endif // _LLCORE_HTTP_OPERATION_H_ diff --git a/indra/llcorehttp/_httpoprequest.cpp b/indra/llcorehttp/_httpoprequest.cpp index 521bd5b879..54b9990057 100644 --- a/indra/llcorehttp/_httpoprequest.cpp +++ b/indra/llcorehttp/_httpoprequest.cpp @@ -93,6 +93,7 @@ HttpOpRequest::HttpOpRequest() mCurlHandle(NULL), mCurlService(NULL), mCurlHeaders(NULL), + mCurlBodyPos(0), mReplyBody(NULL), mReplyOffset(0), mReplyLength(0), @@ -267,12 +268,46 @@ HttpStatus HttpOpRequest::setupGetByteRange(unsigned int policy_id, } -HttpStatus HttpOpRequest::prepareForGet(HttpService * service) +HttpStatus HttpOpRequest::setupPost(unsigned int policy_id, + float priority, + const std::string & url, + BufferArray * body, + HttpOptions * options, + HttpHeaders * headers) +{ + HttpStatus status; + + mProcFlags = 0; + mReqPolicy = policy_id; + mReqPriority = priority; + mReqMethod = HOR_POST; + mReqURL = url; + if (body) + { + body->addRef(); + mReqBody = body; + } + if (headers && ! mReqHeaders) + { + headers->addRef(); + mReqHeaders = headers; + } + if (options && ! mReqOptions) + { + mReqOptions = new HttpOptions(*options); + } + + return status; +} + + +HttpStatus HttpOpRequest::prepareRequest(HttpService * service) { // *FIXME: better error handling later HttpStatus status; mCurlHandle = curl_easy_init(); + // curl_easy_setopt(mCurlHandle, CURLOPT_VERBOSE, 1); curl_easy_setopt(mCurlHandle, CURLOPT_TIMEOUT, 30); curl_easy_setopt(mCurlHandle, CURLOPT_CONNECTTIMEOUT, 30); curl_easy_setopt(mCurlHandle, CURLOPT_NOSIGNAL, 1); @@ -280,20 +315,68 @@ HttpStatus HttpOpRequest::prepareForGet(HttpService * service) curl_easy_setopt(mCurlHandle, CURLOPT_URL, mReqURL.c_str()); curl_easy_setopt(mCurlHandle, CURLOPT_PRIVATE, this); curl_easy_setopt(mCurlHandle, CURLOPT_ENCODING, ""); + // *FIXME: Need to deal with proxy setup... // curl_easy_setopt(handle, CURLOPT_PROXY, ""); + // *FIXME: Revisit this old DNS timeout setting - may no longer be valid curl_easy_setopt(mCurlHandle, CURLOPT_DNS_CACHE_TIMEOUT, 0); + curl_easy_setopt(mCurlHandle, CURLOPT_AUTOREFERER, 1); curl_easy_setopt(mCurlHandle, CURLOPT_FOLLOWLOCATION, 1); + curl_easy_setopt(mCurlHandle, CURLOPT_MAXREDIRS, 10); curl_easy_setopt(mCurlHandle, CURLOPT_WRITEFUNCTION, writeCallback); curl_easy_setopt(mCurlHandle, CURLOPT_WRITEDATA, mCurlHandle); + curl_easy_setopt(mCurlHandle, CURLOPT_READFUNCTION, readCallback); + curl_easy_setopt(mCurlHandle, CURLOPT_READDATA, mCurlHandle); + switch (mReqMethod) + { + case HOR_GET: + curl_easy_setopt(mCurlHandle, CURLOPT_HTTPGET, 1); + break; + + case HOR_POST: + { + curl_easy_setopt(mCurlHandle, CURLOPT_POST, 1); + long data_size(0); + if (mReqBody) + { + mReqBody->seek(0); + data_size = mReqBody->size(); + } + curl_easy_setopt(mCurlHandle, CURLOPT_POSTFIELDS, static_cast<void *>(NULL)); + curl_easy_setopt(mCurlHandle, CURLOPT_POSTFIELDSIZE, data_size); + mCurlHeaders = curl_slist_append(mCurlHeaders, "Transfer-Encoding: chunked"); + mCurlHeaders = curl_slist_append(mCurlHeaders, "Expect:"); + } + break; + + case HOR_PUT: + { + curl_easy_setopt(mCurlHandle, CURLOPT_UPLOAD, 1); + long data_size(0); + if (mReqBody) + { + mReqBody->seek(0); + data_size = mReqBody->size(); + } + curl_easy_setopt(mCurlHandle, CURLOPT_INFILESIZE, data_size); + mCurlHeaders = curl_slist_append(mCurlHeaders, "Transfer-Encoding: chunked"); + mCurlHeaders = curl_slist_append(mCurlHeaders, "Expect:"); + } + break; + + default: + // *FIXME: fail out here + break; + } + if (mReqHeaders) { mCurlHeaders = append_headers_to_slist(mReqHeaders, mCurlHeaders); } mCurlHeaders = curl_slist_append(mCurlHeaders, "Pragma:"); - if (mReqOffset || mReqLength) + if ((mReqOffset || mReqLength) && HOR_GET == mReqMethod) { static const char * fmt1("Range: bytes=%d-%d"); static const char * fmt2("Range: bytes=%d-"); @@ -347,6 +430,32 @@ size_t HttpOpRequest::writeCallback(void * data, size_t size, size_t nmemb, void } +size_t HttpOpRequest::readCallback(void * data, size_t size, size_t nmemb, void * userdata) +{ + CURL * handle(static_cast<CURL *>(userdata)); + HttpOpRequest * op(NULL); + curl_easy_getinfo(handle, CURLINFO_PRIVATE, &op); + // *FIXME: check the pointer + + if (! op->mReqBody) + { + return 0; + } + const size_t req_size(size * nmemb); + const size_t body_size(op->mReqBody->size()); + if (body_size <= op->mCurlBodyPos) + { + // *FIXME: should probably log this event - unexplained + return 0; + } + + const size_t do_size((std::min)(req_size, body_size - op->mCurlBodyPos)); + op->mReqBody->read(static_cast<char *>(data), do_size); + op->mCurlBodyPos += do_size; + return do_size; +} + + size_t HttpOpRequest::headerCallback(void * data, size_t size, size_t nmemb, void * userdata) { static const char status_line[] = "HTTP/"; diff --git a/indra/llcorehttp/_httpoprequest.h b/indra/llcorehttp/_httpoprequest.h index 601937a943..7efed0b1d9 100644 --- a/indra/llcorehttp/_httpoprequest.h +++ b/indra/llcorehttp/_httpoprequest.h @@ -84,12 +84,20 @@ public: HttpOptions * options, HttpHeaders * headers); - HttpStatus prepareForGet(HttpService * service); + HttpStatus setupPost(unsigned int policy_id, + float priority, + const std::string & url, + BufferArray * body, + HttpOptions * options, + HttpHeaders * headers); + + HttpStatus prepareRequest(HttpService * service); virtual HttpStatus cancel(); protected: static size_t writeCallback(void * data, size_t size, size_t nmemb, void * userdata); + static size_t readCallback(void * data, size_t size, size_t nmemb, void * userdata); static size_t headerCallback(void * data, size_t size, size_t nmemb, void * userdata); protected: @@ -112,6 +120,7 @@ public: CURL * mCurlHandle; HttpService * mCurlService; curl_slist * mCurlHeaders; + size_t mCurlBodyPos; // Result data HttpStatus mStatus; diff --git a/indra/llcorehttp/_httpopsetpriority.cpp b/indra/llcorehttp/_httpopsetpriority.cpp new file mode 100644 index 0000000000..dc609421ed --- /dev/null +++ b/indra/llcorehttp/_httpopsetpriority.cpp @@ -0,0 +1,77 @@ +/** + * @file _httpopsetpriority.cpp + * @brief Definitions for internal classes based on HttpOpSetPriority + * + * $LicenseInfo:firstyear=2012&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2012, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "_httpopsetpriority.h" + +#include "httpresponse.h" +#include "httphandler.h" +#include "_httpservice.h" + + +namespace LLCore +{ + + +HttpOpSetPriority::HttpOpSetPriority(HttpHandle handle, unsigned int priority) + : HttpOperation(), + mHandle(handle), + mPriority(priority) +{} + + +HttpOpSetPriority::~HttpOpSetPriority() +{} + + +void HttpOpSetPriority::stageFromRequest(HttpService * service) +{ + // Do operations + if (! service->changePriority(mHandle, mPriority)) + { + // Request not found, fail the final status + mStatus = HttpStatus(HttpStatus::LLCORE, HE_HANDLE_NOT_FOUND); + } + + // Move directly to response queue + addAsReply(); +} + + +void HttpOpSetPriority::visitNotifier(HttpRequest * request) +{ + if (mLibraryHandler) + { + HttpResponse * response = new HttpResponse(); + + response->setStatus(mStatus); + mLibraryHandler->onCompleted(static_cast<HttpHandle>(this), response); + + response->release(); + } +} + + +} // end namespace LLCore diff --git a/indra/llcorehttp/_httpopsetpriority.h b/indra/llcorehttp/_httpopsetpriority.h new file mode 100644 index 0000000000..e5d8e5fc1f --- /dev/null +++ b/indra/llcorehttp/_httpopsetpriority.h @@ -0,0 +1,70 @@ +/** + * @file _httpsetpriority.h + * @brief Internal declarations for HttpSetPriority + * + * $LicenseInfo:firstyear=2012&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2012, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef _LLCORE_HTTP_SETPRIORITY_H_ +#define _LLCORE_HTTP_SETPRIORITY_H_ + + +#include "httpcommon.h" + +#include "_httpoperation.h" +#include "_refcounted.h" + + +namespace LLCore +{ + + +/// HttpOpSetPriority is an immediate request that +/// searches the various queues looking for a given +/// request handle and changing it's priority if +/// found. + +class HttpOpSetPriority : public HttpOperation +{ +public: + HttpOpSetPriority(HttpHandle handle, unsigned int priority); + virtual ~HttpOpSetPriority(); + +private: + HttpOpSetPriority(const HttpOpSetPriority &); // Not defined + void operator=(const HttpOpSetPriority &); // Not defined + +public: + virtual void stageFromRequest(HttpService *); + + virtual void visitNotifier(HttpRequest * request); + +protected: + HttpStatus mStatus; + HttpHandle mHandle; + unsigned int mPriority; +}; // end class HttpOpSetPriority + +} // end namespace LLCore + +#endif // _LLCORE_HTTP_SETPRIORITY_H_ + diff --git a/indra/llcorehttp/_httppolicy.cpp b/indra/llcorehttp/_httppolicy.cpp index d965a6cf3a..873b519c51 100644 --- a/indra/llcorehttp/_httppolicy.cpp +++ b/indra/llcorehttp/_httppolicy.cpp @@ -28,48 +28,113 @@ #include "_httpoprequest.h" #include "_httpservice.h" +#include "_httplibcurl.h" namespace LLCore { - HttpPolicy::HttpPolicy(HttpService * service) : mService(service) -{} +{ + for (int policy_class(0); policy_class < HttpRequest::POLICY_CLASS_LIMIT; ++policy_class) + { + mReadyInClass[policy_class] = 0; + } +} HttpPolicy::~HttpPolicy() { - for (ready_queue_t::reverse_iterator i(mReadyQueue.rbegin()); - mReadyQueue.rend() != i;) + for (int policy_class(0); policy_class < HttpRequest::POLICY_CLASS_LIMIT; ++policy_class) { - ready_queue_t::reverse_iterator cur(i++); - - (*cur)->cancel(); - (*cur)->release(); + HttpReadyQueue & readyq(mReadyQueue[policy_class]); + + while (! readyq.empty()) + { + HttpOpRequest * op(readyq.top()); + + op->cancel(); + op->release(); + mReadyInClass[policy_class]--; + readyq.pop(); + } } - mService = NULL; } void HttpPolicy::addOp(HttpOpRequest * op) { - mReadyQueue.push_back(op); + const int policy_class(op->mReqPolicy); + + mReadyQueue[policy_class].push(op); + ++mReadyInClass[policy_class]; } -void HttpPolicy::processReadyQueue() +HttpService::ELoopSpeed HttpPolicy::processReadyQueue() { - while (! mReadyQueue.empty()) + HttpService::ELoopSpeed result(HttpService::REQUEST_SLEEP); + HttpLibcurl * pTransport(mService->getTransport()); + + for (int policy_class(0); policy_class < HttpRequest::POLICY_CLASS_LIMIT; ++policy_class) { - HttpOpRequest * op(mReadyQueue.front()); - mReadyQueue.erase(mReadyQueue.begin()); + HttpReadyQueue & readyq(mReadyQueue[policy_class]); + int active(pTransport->getActiveCountInClass(policy_class)); + int needed(8 - active); + + if (needed > 0 && mReadyInClass[policy_class] > 0) + { + // Scan ready queue for requests that match policy + + while (! readyq.empty() && needed > 0 && mReadyInClass[policy_class] > 0) + { + HttpOpRequest * op(readyq.top()); + readyq.pop(); + + op->stageFromReady(mService); + op->release(); + + --mReadyInClass[policy_class]; + --needed; + } + } + + if (! readyq.empty()) + { + // If anything is ready, continue looping... + result = (std::min)(result, HttpService::NORMAL); + } + } + + return result; +} - op->stageFromReady(mService); - op->release(); + +bool HttpPolicy::changePriority(HttpHandle handle, unsigned int priority) +{ + for (int policy_class(0); policy_class < HttpRequest::POLICY_CLASS_LIMIT; ++policy_class) + { + HttpReadyQueue::container_type & c(mReadyQueue[policy_class].get_container()); + + // Scan ready queue for requests that match policy + for (HttpReadyQueue::container_type::iterator iter(c.begin()); c.end() != iter;) + { + HttpReadyQueue::container_type::iterator cur(iter++); + + if (static_cast<HttpHandle>(*cur) == handle) + { + HttpOpRequest * op(*cur); + c.erase(cur); // All iterators are now invalidated + op->mReqPriority = priority; + mReadyQueue[policy_class].push(op); // Re-insert using adapter class + return true; + } + } } + + return false; } diff --git a/indra/llcorehttp/_httppolicy.h b/indra/llcorehttp/_httppolicy.h index 192bc73b31..c5e82d0a65 100644 --- a/indra/llcorehttp/_httppolicy.h +++ b/indra/llcorehttp/_httppolicy.h @@ -28,18 +28,23 @@ #define _LLCORE_HTTP_POLICY_H_ -#include <vector> +#include "httprequest.h" +#include "_httpservice.h" +#include "_httpreadyqueue.h" namespace LLCore { - -class HttpService; +class HttpReadyQueue; class HttpOpRequest; /// Implements class-based queuing policies for an HttpService instance. +/// +/// Threading: Single-threaded. Other than for construction/destruction, +/// all methods are expected to be invoked in a single thread, typically +/// a worker thread of some sort. class HttpPolicy { public: @@ -51,16 +56,23 @@ private: void operator=(const HttpPolicy &); // Not defined public: - void processReadyQueue(); + /// Give the policy layer some cycles to scan the ready + /// queue promoting higher-priority requests to active + /// as permited. + HttpService::ELoopSpeed processReadyQueue(); + /// Add request to a ready queue. Caller is expected to have + /// provided us with a reference count to hold the request. (No + /// additional references will be added.) void addOp(HttpOpRequest *); + + // Shadows HttpService's method + bool changePriority(HttpHandle handle, unsigned int priority); protected: - typedef std::vector<HttpOpRequest *> ready_queue_t; - -protected: + int mReadyInClass[HttpRequest::POLICY_CLASS_LIMIT]; + HttpReadyQueue mReadyQueue[HttpRequest::POLICY_CLASS_LIMIT]; HttpService * mService; // Naked pointer, not refcounted, not owner - ready_queue_t mReadyQueue; }; // end class HttpPolicy diff --git a/indra/llcorehttp/_httpreadyqueue.h b/indra/llcorehttp/_httpreadyqueue.h new file mode 100644 index 0000000000..283e868b4c --- /dev/null +++ b/indra/llcorehttp/_httpreadyqueue.h @@ -0,0 +1,85 @@ +/** + * @file _httpreadyqueue.h + * @brief Internal declaration for the operation ready queue + * + * $LicenseInfo:firstyear=2012&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2012, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef _LLCORE_HTTP_READY_QUEUE_H_ +#define _LLCORE_HTTP_READY_QUEUE_H_ + + +#include <queue> + +#include "_httpoperation.h" + + +namespace LLCore +{ + +class HttpOpRequest; + +/// HttpReadyQueue provides a simple priority queue for HttpOpRequest objects. +/// +/// This uses the priority_queue adaptor class to provide the queue +/// as well as the ordering scheme while allowing us access to the +/// raw container if we follow a few simple rules. One of the more +/// important of those rules is that any iterator becomes invalid +/// on element erasure. So pay attention. +/// +/// Threading: not thread-safe. Expected to be used entirely by +/// a single thread, typically a worker thread of some sort. + +class HttpReadyQueue : public std::priority_queue<HttpOpRequest *, + std::deque<HttpOpRequest *>, + LLCore::HttpOpCompare> +{ +public: + HttpReadyQueue() + : priority_queue() + {} + + ~HttpReadyQueue() + {} + +protected: + HttpReadyQueue(const HttpReadyQueue &); // Not defined + void operator=(const HttpReadyQueue &); // Not defined + +public: + const container_type & get_container() const + { + return c; + } + + container_type & get_container() + { + return c; + } + +}; // end class HttpReadyQueue + + +} // end namespace LLCore + + +#endif // _LLCORE_HTTP_READY_QUEUE_H_ diff --git a/indra/llcorehttp/_httprequestqueue.cpp b/indra/llcorehttp/_httprequestqueue.cpp index c36814aee3..92bb5ec5c1 100644 --- a/indra/llcorehttp/_httprequestqueue.cpp +++ b/indra/llcorehttp/_httprequestqueue.cpp @@ -57,7 +57,7 @@ HttpRequestQueue::~HttpRequestQueue() void HttpRequestQueue::init() { - LLINT_ASSERT(! sInstance); + llassert_always(! sInstance); sInstance = new HttpRequestQueue(); } diff --git a/indra/llcorehttp/_httpservice.cpp b/indra/llcorehttp/_httpservice.cpp index 6ebc0ec6cb..48884ca060 100644 --- a/indra/llcorehttp/_httpservice.cpp +++ b/indra/llcorehttp/_httpservice.cpp @@ -35,6 +35,8 @@ #include "_httplibcurl.h" #include "_thread.h" +#include "lltimer.h" + namespace LLCore { @@ -89,8 +91,8 @@ HttpService::~HttpService() void HttpService::init(HttpRequestQueue * queue) { - LLINT_ASSERT(! sInstance); - LLINT_ASSERT(NOT_INITIALIZED == sState); + llassert_always(! sInstance); + llassert_always(NOT_INITIALIZED == sState); sInstance = new HttpService(); queue->addRef(); @@ -103,7 +105,7 @@ void HttpService::init(HttpRequestQueue * queue) void HttpService::term() { - LLINT_ASSERT(RUNNING != sState); + llassert_always(RUNNING != sState); if (sInstance) { delete sInstance; @@ -132,8 +134,8 @@ bool HttpService::isStopped() void HttpService::startThread() { - LLINT_ASSERT(! mThread || STOPPED == sState); - LLINT_ASSERT(INITIALIZED == sState || STOPPED == sState); + llassert_always(! mThread || STOPPED == sState); + llassert_always(INITIALIZED == sState || STOPPED == sState); if (mThread) { @@ -150,6 +152,20 @@ void HttpService::stopRequested() mExitRequested = true; } +bool HttpService::changePriority(HttpHandle handle, unsigned int priority) +{ + bool found(false); + + // Skip the request queue as we currently don't leave earlier + // requests sitting there. Start with the ready queue... + found = mPolicy->changePriority(handle, priority); + + // If not there, we could try the transport/active queue but priority + // doesn't really have much effect there so we don't waste cycles. + + return found; +} + void HttpService::shutdown() { @@ -157,38 +173,46 @@ void HttpService::shutdown() } +// Working thread loop-forever method. Gives time to +// each of the request queue, policy layer and transport +// layer pieces and then either sleeps for a small time +// or waits for a request to come in. Repeats until +// requested to stop. void HttpService::threadRun(LLCoreInt::HttpThread * thread) { boost::this_thread::disable_interruption di; - + ELoopSpeed loop(REQUEST_SLEEP); + while (! mExitRequested) { - processRequestQueue(); + loop = processRequestQueue(loop); // Process ready queue issuing new requests as needed - mPolicy->processReadyQueue(); + ELoopSpeed new_loop = mPolicy->processReadyQueue(); + loop = (std::min)(loop, new_loop); // Give libcurl some cycles - mTransport->processTransport(); + new_loop = mTransport->processTransport(); + loop = (std::min)(loop, new_loop); // Determine whether to spin, sleep briefly or sleep for next request - // *FIXME: For now, do this -#if defined(WIN32) - Sleep(50); -#else - usleep(5000); -#endif + if (REQUEST_SLEEP != loop) + { + ms_sleep(50); + } } + shutdown(); sState = STOPPED; } -void HttpService::processRequestQueue() +HttpService::ELoopSpeed HttpService::processRequestQueue(ELoopSpeed loop) { HttpRequestQueue::OpContainer ops; - - mRequestQueue->fetchAll(false, ops); + const bool wait_for_req(REQUEST_SLEEP == loop); + + mRequestQueue->fetchAll(wait_for_req, ops); while (! ops.empty()) { HttpOperation * op(ops.front()); @@ -203,6 +227,9 @@ void HttpService::processRequestQueue() // Done with operation op->release(); } + + // Queue emptied, allow polling loop to sleep + return REQUEST_SLEEP; } diff --git a/indra/llcorehttp/_httpservice.h b/indra/llcorehttp/_httpservice.h index ba76e1eeca..3e5a5457d7 100644 --- a/indra/llcorehttp/_httpservice.h +++ b/indra/llcorehttp/_httpservice.h @@ -28,6 +28,9 @@ #define _LLCORE_HTTP_SERVICE_H_ +#include "httpcommon.h" + + namespace LLCoreInt { @@ -86,7 +89,17 @@ public: RUNNING, ///< thread created and running STOPPED ///< thread has committed to exiting }; - + + // Ordered enumeration of idling strategies available to + // threadRun's loop. Ordered so that std::min on values + // produces the most conservative result of multiple + // requests. + enum ELoopSpeed + { + NORMAL, ///< continuous polling of request, ready, active queues + REQUEST_SLEEP ///< can sleep indefinitely waiting for request queue write + }; + static void init(HttpRequestQueue *); static void term(); @@ -124,6 +137,15 @@ public: /// Threading: callable by worker thread. void shutdown(); + + /// Try to find the given request handle on any of the request + /// queues and reset the priority (and queue position) of the + /// request if found. + /// + /// @return True if the request was found somewhere. + /// + /// Threading: callable by worker thread. + bool changePriority(HttpHandle handle, unsigned int priority); HttpPolicy * getPolicy() { @@ -138,7 +160,7 @@ public: protected: void threadRun(LLCoreInt::HttpThread * thread); - void processRequestQueue(); + ELoopSpeed processRequestQueue(ELoopSpeed loop); protected: static HttpService * sInstance; diff --git a/indra/llcorehttp/_refcounted.h b/indra/llcorehttp/_refcounted.h index 4a6ce8420a..72cef6b342 100644 --- a/indra/llcorehttp/_refcounted.h +++ b/indra/llcorehttp/_refcounted.h @@ -30,7 +30,7 @@ #include <boost/thread.hpp> -#include "_assert.h" +#include "linden_common.h" namespace LLCoreInt @@ -71,7 +71,7 @@ private: inline void RefCounted::addRef() const { boost::mutex::scoped_lock lock(mRefLock); - LLINT_ASSERT(mRefCount >= 0); + llassert_always(mRefCount >= 0); ++mRefCount; } @@ -82,8 +82,8 @@ inline void RefCounted::release() const { // CRITICAL SECTION boost::mutex::scoped_lock lock(mRefLock); - LLINT_ASSERT(mRefCount != NOT_REF_COUNTED); - LLINT_ASSERT(mRefCount > 0); + llassert_always(mRefCount != NOT_REF_COUNTED); + llassert_always(mRefCount > 0); count = --mRefCount; // CRITICAL SECTION } @@ -104,8 +104,8 @@ inline bool RefCounted::isLastRef() const // CRITICAL SECTION boost::mutex::scoped_lock lock(mRefLock); - LLINT_ASSERT(mRefCount != NOT_REF_COUNTED); - LLINT_ASSERT(mRefCount >= 1); + llassert_always(mRefCount != NOT_REF_COUNTED); + llassert_always(mRefCount >= 1); count = mRefCount; // CRITICAL SECTION } @@ -125,7 +125,7 @@ inline int RefCounted::getRefCount() const inline void RefCounted::noRef() const { boost::mutex::scoped_lock lock(mRefLock); - LLINT_ASSERT(mRefCount <= 1); + llassert_always(mRefCount <= 1); mRefCount = NOT_REF_COUNTED; } diff --git a/indra/llcorehttp/httpcommon.cpp b/indra/llcorehttp/httpcommon.cpp index b5872606b8..273acae132 100644 --- a/indra/llcorehttp/httpcommon.cpp +++ b/indra/llcorehttp/httpcommon.cpp @@ -28,6 +28,7 @@ #include <curl/curl.h> #include <string> +#include <sstream> namespace LLCore @@ -46,6 +47,16 @@ HttpStatus::operator unsigned long() const } +std::string HttpStatus::toHex() const +{ + std::ostringstream result; + result.width(8); + result.fill('0'); + result << std::hex << operator unsigned long(); + return result.str(); + +} + std::string HttpStatus::toString() const { static const char * llcore_errors[] = @@ -54,7 +65,8 @@ std::string HttpStatus::toString() const "HTTP error reply status", "Services shutting down", "Operation canceled", - "Invalid Content-Range header encountered" + "Invalid Content-Range header encountered", + "Request handle not found" }; static const int llcore_errors_count(sizeof(llcore_errors) / sizeof(llcore_errors[0])); @@ -131,6 +143,7 @@ std::string HttpStatus::toString() const default: if (isHttpStatus()) { + // Binary search for the error code and string int bottom(0), top(http_errors_count); while (true) { diff --git a/indra/llcorehttp/httpcommon.h b/indra/llcorehttp/httpcommon.h index f81be7103e..c01a5f85d3 100644 --- a/indra/llcorehttp/httpcommon.h +++ b/indra/llcorehttp/httpcommon.h @@ -134,7 +134,10 @@ enum HttpError HE_OP_CANCELED = 3, // Invalid content range header received. - HE_INV_CONTENT_RANGE_HDR = 4 + HE_INV_CONTENT_RANGE_HDR = 4, + + // Request handle not found + HE_HANDLE_NOT_FOUND = 5 }; // end enum HttpError @@ -229,6 +232,9 @@ struct HttpStatus { return operator unsigned long(); } + + /// And to convert to a hex string. + std::string toHex() const; /// Convert status to a string representation. For /// success, returns an empty string. For failure diff --git a/indra/llcorehttp/httprequest.cpp b/indra/llcorehttp/httprequest.cpp index 6c62f931ff..a06b859a91 100644 --- a/indra/llcorehttp/httprequest.cpp +++ b/indra/llcorehttp/httprequest.cpp @@ -31,6 +31,7 @@ #include "_httpservice.h" #include "_httpoperation.h" #include "_httpoprequest.h" +#include "_httpopsetpriority.h" #include "_httpopcancel.h" @@ -162,7 +163,7 @@ HttpStatus HttpRequest::getStatus() const HttpHandle HttpRequest::requestGetByteRange(unsigned int policy_id, - float priority, + unsigned int priority, const std::string & url, size_t offset, size_t len, @@ -190,6 +191,34 @@ HttpHandle HttpRequest::requestGetByteRange(unsigned int policy_id, } +HttpHandle HttpRequest::requestPost(unsigned int policy_id, + unsigned int priority, + const std::string & url, + BufferArray * body, + HttpOptions * options, + HttpHeaders * headers, + HttpHandler * user_handler) +{ + HttpStatus status; + HttpHandle handle(LLCORE_HTTP_HANDLE_INVALID); + + HttpOpRequest * op = new HttpOpRequest(); + if (! (status = op->setupPost(policy_id, priority, url, body, options, headers))) + { + op->release(); + mLastReqStatus = status; + return handle; + } + op->setHandlers(mReplyQueue, mSelfHandler, user_handler); + mRequestQueue->addOp(op); // transfers refcount + + mLastReqStatus = status; + handle = static_cast<HttpHandle>(op); + + return handle; +} + + HttpHandle HttpRequest::requestCancel(HttpHandle handle, HttpHandler * user_handler) { HttpStatus status; @@ -222,6 +251,23 @@ HttpHandle HttpRequest::requestNoOp(HttpHandler * user_handler) } +HttpHandle HttpRequest::requestSetPriority(HttpHandle request, unsigned int priority, + HttpHandler * handler) +{ + HttpStatus status; + HttpHandle ret_handle(LLCORE_HTTP_HANDLE_INVALID); + + HttpOpSetPriority * op = new HttpOpSetPriority(request, priority); + op->setHandlers(mReplyQueue, mSelfHandler, handler); + mRequestQueue->addOp(op); // transfer refcount as well + + mLastReqStatus = status; + ret_handle = static_cast<HttpHandle>(op); + + return ret_handle; +} + + HttpStatus HttpRequest::update(long millis) { HttpStatus status; @@ -259,7 +305,7 @@ HttpStatus HttpRequest::createService() { HttpStatus status; - LLINT_ASSERT(! has_inited); + llassert_always(! has_inited); HttpRequestQueue::init(); HttpRequestQueue * rq = HttpRequestQueue::instanceOf(); HttpService::init(rq); @@ -273,7 +319,7 @@ HttpStatus HttpRequest::destroyService() { HttpStatus status; - LLINT_ASSERT(has_inited); + llassert_always(has_inited); HttpService::term(); HttpRequestQueue::term(); has_inited = false; diff --git a/indra/llcorehttp/httprequest.h b/indra/llcorehttp/httprequest.h index 4bbd13a13a..e2ab9be533 100644 --- a/indra/llcorehttp/httprequest.h +++ b/indra/llcorehttp/httprequest.h @@ -41,6 +41,7 @@ class HttpService; class HttpOptions; class HttpHeaders; class HttpOperation; +class BufferArray; /// HttpRequest supplies the entry into the HTTP transport /// services in the LLCore libraries. Services provided include: @@ -96,6 +97,10 @@ public: /// Represents a default, catch-all policy class that guarantees /// eventual service for any HTTP request. static const int DEFAULT_POLICY_ID = 0; + + /// Maximum number of policies that may be defined. No policy + /// ID will equal or exceed this value. + static const int POLICY_CLASS_LIMIT = 1; enum EGlobalPolicy { @@ -177,7 +182,7 @@ public: /// @param policy_id Default or user-defined policy class under /// which this request is to be serviced. /// @param priority Standard priority scheme inherited from - /// Indra code base. + /// Indra code base (U32-type scheme). /// @param url /// @param offset /// @param len @@ -190,7 +195,7 @@ public: /// case, @see getStatus() will return more info. /// HttpHandle requestGetByteRange(unsigned int policy_id, - float priority, + unsigned int priority, const std::string & url, size_t offset, size_t len, @@ -199,6 +204,32 @@ public: HttpHandler * handler); + /// + /// @param policy_id Default or user-defined policy class under + /// which this request is to be serviced. + /// @param priority Standard priority scheme inherited from + /// Indra code base. + /// @param url + /// @param body Byte stream to be sent as the body. No + /// further encoding or escaping will be done + /// to the content. + /// @param options (optional) + /// @param headers (optional) + /// @param handler (optional) + /// @return The handle of the request if successfully + /// queued or LLCORE_HTTP_HANDLE_INVALID if the + /// request could not be queued. In the latter + /// case, @see getStatus() will return more info. + /// + HttpHandle requestPost(unsigned int policy_id, + unsigned int priority, + const std::string & url, + BufferArray * body, + HttpOptions * options, + HttpHeaders * headers, + HttpHandler * handler); + + /// Queue a NoOp request. /// The request is queued and serviced by the working thread which /// immediately processes it and returns the request to the reply @@ -235,6 +266,20 @@ public: HttpHandle requestCancel(HttpHandle request, HttpHandler *); + /// Request that a previously-issued request be reprioritized. + /// The status of whether the change itself succeeded arrives + /// via notification. + /// + /// @param request Handle of previously-issued request to + /// be changed. + /// @param priority New priority value. + /// @param handler (optional) + /// @return The handle of the request if successfully + /// queued or LLCORE_HTTP_HANDLE_INVALID if the + /// request could not be queued. + /// + HttpHandle requestSetPriority(HttpHandle request, unsigned int priority, HttpHandler * handler); + /// @} /// @name UtilityMethods diff --git a/indra/llcorehttp/tests/test_httprequest.hpp b/indra/llcorehttp/tests/test_httprequest.hpp index a73d90957e..0e9d7d8979 100644 --- a/indra/llcorehttp/tests/test_httprequest.hpp +++ b/indra/llcorehttp/tests/test_httprequest.hpp @@ -370,7 +370,7 @@ void HttpRequestTestObjectType::test<5>() // Issue a GET that can't connect mStatus = HttpStatus(HttpStatus::EXT_CURL_EASY, CURLE_COULDNT_CONNECT); HttpHandle handle = req->requestGetByteRange(HttpRequest::DEFAULT_POLICY_ID, - 0.0f, + 0U, "http://127.0.0.1:2/nothing/here", 0, 0, diff --git a/indra/newview/lltexturefetch.cpp b/indra/newview/lltexturefetch.cpp index 17c68f7c22..381364b5c3 100644 --- a/indra/newview/lltexturefetch.cpp +++ b/indra/newview/lltexturefetch.cpp @@ -51,6 +51,7 @@ #include "llviewerstats.h" #include "llviewerassetstats.h" #include "llworld.h" +#include "llsdserialize.h" #include "httprequest.h" #include "httphandler.h" @@ -748,7 +749,7 @@ void LLTextureFetchWorker::setImagePriority(F32 priority) { mImagePriority = priority; calcWorkPriority(); - U32 work_priority = mWorkPriority | LLWorkerThread::PRIORITY_LOW; + U32 work_priority = mWorkPriority | (getPriority() & LLWorkerThread::PRIORITY_HIGHBITS); setPriority(work_priority); } } @@ -855,7 +856,6 @@ bool LLTextureFetchWorker::doWork(S32 param) if (mState == LOAD_FROM_TEXTURE_CACHE) { - setPriority(0); // Set priority first since Responder may change it if (mCacheReadHandle == LLTextureCache::nullHandle()) { U32 cache_priority = mWorkPriority; @@ -871,6 +871,8 @@ bool LLTextureFetchWorker::doWork(S32 param) if (mUrl.compare(0, 7, "file://") == 0) { + setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority); // Set priority first since Responder may change it + // read file from local disk std::string filename = mUrl.substr(7, std::string::npos); CacheReadResponder* responder = new CacheReadResponder(mFetcher, mID, mFormattedImage); @@ -879,6 +881,8 @@ bool LLTextureFetchWorker::doWork(S32 param) } else if (mUrl.empty()) { + setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority); // Set priority first since Responder may change it + CacheReadResponder* responder = new CacheReadResponder(mFetcher, mID, mFormattedImage); mCacheReadHandle = mFetcher->mTextureCache->readFromCache(mID, cache_priority, offset, size, responder); @@ -890,12 +894,12 @@ bool LLTextureFetchWorker::doWork(S32 param) // *TODO:?remove this warning llwarns << "Unknown URL Type: " << mUrl << llendl; } - setPriority(LLWorkerThread::PRIORITY_HIGH); + setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority); mState = SEND_HTTP_REQ; } else { - setPriority(LLWorkerThread::PRIORITY_HIGH); + setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority); mState = LOAD_FROM_NETWORK; } } @@ -907,7 +911,6 @@ bool LLTextureFetchWorker::doWork(S32 param) { mCacheReadHandle = LLTextureCache::nullHandle(); mState = CACHE_POST; - setPriority(LLWorkerThread::PRIORITY_HIGH); // fall through } else @@ -931,7 +934,6 @@ bool LLTextureFetchWorker::doWork(S32 param) llassert_always(mFormattedImage->getDataSize() > 0); mLoadedDiscard = mDesiredDiscard; mState = DECODE_IMAGE; - setPriority(LLWorkerThread::PRIORITY_HIGH); mWriteToCacheState = NOT_WRITE ; LL_DEBUGS("Texture") << mID << ": Cached. Bytes: " << mFormattedImage->getDataSize() << " Size: " << llformat("%dx%d",mFormattedImage->getWidth(),mFormattedImage->getHeight()) @@ -949,7 +951,6 @@ bool LLTextureFetchWorker::doWork(S32 param) else { LL_DEBUGS("Texture") << mID << ": Not in Cache" << LL_ENDL; - setPriority(LLWorkerThread::PRIORITY_HIGH); mState = LOAD_FROM_NETWORK; } // fall through @@ -960,7 +961,6 @@ bool LLTextureFetchWorker::doWork(S32 param) { static LLCachedControl<bool> use_http(gSavedSettings,"ImagePipelineUseHTTP"); - setPriority(0); // if (mHost != LLHost::invalid) get_url = false; if ( use_http && mCanUseHTTP && mUrl.empty())//get http url. { @@ -993,7 +993,7 @@ bool LLTextureFetchWorker::doWork(S32 param) if (mCanUseHTTP && !mUrl.empty()) { mState = SEND_HTTP_REQ; - setPriority(LLWorkerThread::PRIORITY_HIGH); + setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority); if(mWriteToCacheState != NOT_WRITE) { mWriteToCacheState = CAN_WRITE ; @@ -1010,6 +1010,7 @@ bool LLTextureFetchWorker::doWork(S32 param) mSentRequest = QUEUED; mFetcher->addToNetworkQueue(this); recordTextureStart(false); + setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority); return false; } @@ -1027,7 +1028,6 @@ bool LLTextureFetchWorker::doWork(S32 param) if (mState == LOAD_FROM_SIMULATOR) { - setPriority(0); if (mFormattedImage.isNull()) { mFormattedImage = new LLImageJ2C; @@ -1042,7 +1042,7 @@ bool LLTextureFetchWorker::doWork(S32 param) // llwarns << "processSimulatorPackets() failed to load buffer" << llendl; return true; // failed } - setPriority(LLWorkerThread::PRIORITY_HIGH); + setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority); mState = DECODE_IMAGE; mWriteToCacheState = SHOULD_WRITE; recordTextureDone(false); @@ -1050,6 +1050,7 @@ bool LLTextureFetchWorker::doWork(S32 param) else { mFetcher->addToNetworkQueue(this); // failsafe + setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority); recordTextureStart(false); } return false; @@ -1057,7 +1058,6 @@ bool LLTextureFetchWorker::doWork(S32 param) if (mState == SEND_HTTP_REQ) { - setPriority(0); if(mCanUseHTTP) { //NOTE: @@ -1065,11 +1065,13 @@ bool LLTextureFetchWorker::doWork(S32 param) //1, not openning too many file descriptors at the same time; //2, control the traffic of http so udp gets bandwidth. // - static const S32 MAX_NUM_OF_HTTP_REQUESTS_IN_QUEUE = 8 ; - if(mFetcher->getNumHTTPRequests() > MAX_NUM_OF_HTTP_REQUESTS_IN_QUEUE) - { - return false ; //wait. - } + static const S32 MAX_NUM_OF_HTTP_REQUESTS_IN_QUEUE = 8; + // *FIXME: For the moment, allow everything to transition into HTTP + // and have the new library order and throttle. + //if(mFetcher->getNumHTTPRequests() > MAX_NUM_OF_HTTP_REQUESTS_IN_QUEUE) + //{ + //return false ; //wait. + //} mFetcher->removeFromNetworkQueue(this, false); @@ -1083,7 +1085,6 @@ bool LLTextureFetchWorker::doWork(S32 param) { // We already have all the data, just decode it mLoadedDiscard = mFormattedImage->getDiscardLevel(); - setPriority(LLWorkerThread::PRIORITY_HIGH); mState = DECODE_IMAGE; return false; } @@ -1135,7 +1136,7 @@ bool LLTextureFetchWorker::doWork(S32 param) mHttpActive = true; mFetcher->addToHTTPQueue(mID); recordTextureStart(true); - setPriority(LLWorkerThread::PRIORITY_HIGH); + setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority); mState = WAIT_HTTP_REQ; // fall through @@ -1148,7 +1149,6 @@ bool LLTextureFetchWorker::doWork(S32 param) if (mState == WAIT_HTTP_REQ) { - setPriority(0); if (mLoaded) { S32 cur_size = mFormattedImage.notNull() ? mFormattedImage->getDataSize() : 0; @@ -1165,7 +1165,7 @@ bool LLTextureFetchWorker::doWork(S32 param) { mState = INIT; mCanUseHTTP = false; - setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority); + setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority); return false; } } @@ -1184,7 +1184,8 @@ bool LLTextureFetchWorker::doWork(S32 param) max_attempts = HTTP_MAX_RETRY_COUNT + 1; ++mHTTPFailCount; llinfos << "HTTP GET failed for: " << mUrl - << " Status: " << mGetStatus.toULong() << " Reason: '" << mGetReason << "'" + << " Status: " << mGetStatus.toHex() + << " Reason: '" << mGetReason << "'" << " Attempt:" << mHTTPFailCount+1 << "/" << max_attempts << llendl; } @@ -1194,14 +1195,12 @@ bool LLTextureFetchWorker::doWork(S32 param) { // Use available data mLoadedDiscard = mFormattedImage->getDiscardLevel(); - setPriority(LLWorkerThread::PRIORITY_HIGH); mState = DECODE_IMAGE; return false; } else { resetFormattedData(); - setPriority(LLWorkerThread::PRIORITY_HIGH); mState = DONE; return true; // failed } @@ -1223,7 +1222,6 @@ bool LLTextureFetchWorker::doWork(S32 param) } // abort. - setPriority(LLWorkerThread::PRIORITY_HIGH); mState = DONE; return true; } @@ -1268,29 +1266,30 @@ bool LLTextureFetchWorker::doWork(S32 param) mHttpBufferArray = NULL; mLoadedDiscard = mRequestedDiscard; - setPriority(LLWorkerThread::PRIORITY_HIGH); mState = DECODE_IMAGE; if (mWriteToCacheState != NOT_WRITE) { mWriteToCacheState = SHOULD_WRITE ; } + setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority); return false; } else { + setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority); return false; } } if (mState == DECODE_IMAGE) { - setPriority(0); static LLCachedControl<bool> textures_decode_disabled(gSavedSettings,"TextureDecodeDisabled"); + + setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority); // Set priority first since Responder may change it if (textures_decode_disabled) { // for debug use, don't decode mState = DONE; - setPriority(LLWorkerThread::PRIORITY_HIGH); return true; } @@ -1298,7 +1297,6 @@ bool LLTextureFetchWorker::doWork(S32 param) { // We aborted, don't decode mState = DONE; - setPriority(LLWorkerThread::PRIORITY_HIGH); return true; } @@ -1308,7 +1306,6 @@ bool LLTextureFetchWorker::doWork(S32 param) //abort, don't decode mState = DONE; - setPriority(LLWorkerThread::PRIORITY_HIGH); return true; } if (mLoadedDiscard < 0) @@ -1317,7 +1314,6 @@ bool LLTextureFetchWorker::doWork(S32 param) //abort, don't decode mState = DONE; - setPriority(LLWorkerThread::PRIORITY_HIGH); return true; } @@ -1337,7 +1333,6 @@ bool LLTextureFetchWorker::doWork(S32 param) if (mState == DECODE_IMAGE_UPDATE) { - setPriority(0); if (mDecoded) { if (mDecodedDiscard < 0) @@ -1350,14 +1345,13 @@ bool LLTextureFetchWorker::doWork(S32 param) llassert_always(mDecodeHandle == 0); mFormattedImage = NULL; ++mRetryAttempt; - setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority); + setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority); mState = INIT; return false; } else { // llwarns << "UNABLE TO LOAD TEXTURE: " << mID << " RETRIES: " << mRetryAttempt << llendl; - setPriority(LLWorkerThread::PRIORITY_HIGH); mState = DONE; // failed } } @@ -1366,7 +1360,7 @@ bool LLTextureFetchWorker::doWork(S32 param) llassert_always(mRawImage.notNull()); LL_DEBUGS("Texture") << mID << ": Decoded. Discard: " << mDecodedDiscard << " Raw Image: " << llformat("%dx%d",mRawImage->getWidth(),mRawImage->getHeight()) << LL_ENDL; - setPriority(LLWorkerThread::PRIORITY_HIGH); + setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority); mState = WRITE_TO_CACHE; } // fall through @@ -1379,12 +1373,10 @@ bool LLTextureFetchWorker::doWork(S32 param) if (mState == WRITE_TO_CACHE) { - setPriority(0); if (mWriteToCacheState != SHOULD_WRITE || mFormattedImage.isNull()) { // If we're in a local cache or we didn't actually receive any new data, // or we failed to load anything, skip - setPriority(LLWorkerThread::PRIORITY_HIGH); mState = DONE; return false; } @@ -1404,7 +1396,6 @@ bool LLTextureFetchWorker::doWork(S32 param) setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority); // Set priority first since Responder may change it U32 cache_priority = mWorkPriority; mWritten = FALSE; - setPriority(LLWorkerThread::PRIORITY_HIGH); mState = WAIT_ON_WRITE; CacheWriteResponder* responder = new CacheWriteResponder(mFetcher, mID); mCacheWriteHandle = mFetcher->mTextureCache->writeToCache(mID, cache_priority, @@ -1415,10 +1406,8 @@ bool LLTextureFetchWorker::doWork(S32 param) if (mState == WAIT_ON_WRITE) { - setPriority(0); if (writeToCacheComplete()) { - setPriority(LLWorkerThread::PRIORITY_HIGH); mState = DONE; // fall through } @@ -1437,15 +1426,16 @@ bool LLTextureFetchWorker::doWork(S32 param) if (mState == DONE) { - setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority); if (mDecodedDiscard >= 0 && mDesiredDiscard < mDecodedDiscard) { // More data was requested, return to INIT mState = INIT; + setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority); return false; } else { + setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority); return true; } } @@ -1477,7 +1467,8 @@ void LLTextureFetchWorker::onCompleted(LLCore::HttpHandle handle, LLCore::HttpRe LLCore::HttpStatus status(response->getStatus()); lldebugs << "HTTP COMPLETE: " << mID - << " status: " << status.toULong() << " '" << status.toString() << "'" + << " status: " << status.toHex() + << " '" << status.toString() << "'" << llendl; unsigned int offset(0), length(0); response->getRange(&offset, &length); @@ -1492,7 +1483,8 @@ void LLTextureFetchWorker::onCompleted(LLCore::HttpHandle handle, LLCore::HttpRe success = false; std::string reason(status.toString()); setGetStatus(status, reason); - llwarns << "CURL GET FAILED, status:" << status.toULong() << " reason:" << reason << llendl; + llwarns << "CURL GET FAILED, status: " << status.toHex() + << " reason: " << reason << llendl; } else { @@ -1727,7 +1719,7 @@ S32 LLTextureFetchWorker::callbackHttpGet(LLCore::HttpResponse * response, mRequestedSize = -1; // error } mLoaded = TRUE; - setPriority(LLWorkerThread::PRIORITY_HIGH); + setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority); return data_size ; } @@ -1756,7 +1748,7 @@ void LLTextureFetchWorker::callbackCacheRead(bool success, LLImageFormatted* ima } } mLoaded = TRUE; - setPriority(LLWorkerThread::PRIORITY_HIGH); + setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority); } void LLTextureFetchWorker::callbackCacheWrite(bool success) @@ -1768,7 +1760,7 @@ void LLTextureFetchWorker::callbackCacheWrite(bool success) return; } mWritten = TRUE; - setPriority(LLWorkerThread::PRIORITY_HIGH); + setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority); } ////////////////////////////////////////////////////////////////////////////// @@ -1806,7 +1798,7 @@ void LLTextureFetchWorker::callbackDecoded(bool success, LLImageRaw* raw, LLImag } mDecoded = TRUE; // llinfos << mID << " : DECODE COMPLETE " << llendl; - setPriority(LLWorkerThread::PRIORITY_HIGH); + setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority); } ////////////////////////////////////////////////////////////////////////////// @@ -1883,7 +1875,6 @@ LLTextureFetch::LLTextureFetch(LLTextureCache* cache, LLImageDecodeThread* image mHttpOptions(NULL), mHttpHeaders(NULL) { - mCurlPOSTRequestCount = 0; mMaxBandwidth = gSavedSettings.getF32("ThrottleBandwidthKBPS"); mTextureInfo.setUpLogging(gSavedSettings.getBOOL("LogTextureDownloadsToViewerLog"), gSavedSettings.getBOOL("LogTextureDownloadsToSimulator"), gSavedSettings.getU32("TextureLoggingThreshold")); @@ -2253,7 +2244,6 @@ S32 LLTextureFetch::getPending() LLMutexLock lock(&mQueueMutex); res = mRequestQueue.size(); - res += mCurlPOSTRequestCount; res += mCommands.size(); } unlockData(); @@ -2279,10 +2269,7 @@ bool LLTextureFetch::runCondition() have_no_commands = mCommands.empty(); } - bool have_no_curl_requests(0 == mCurlPOSTRequestCount); - return ! (have_no_commands - && have_no_curl_requests && (mRequestQueue.empty() && mIdleThread)); // From base class } @@ -2690,7 +2677,7 @@ bool LLTextureFetch::receiveImageHeader(const LLHost& host, const LLUUID& id, U8 llassert_always(totalbytes > 0); llassert_always(data_size == FIRST_PACKET_SIZE || data_size == worker->mFileSize); res = worker->insertPacket(0, data, data_size); - worker->setPriority(LLWorkerThread::PRIORITY_HIGH); + worker->setPriority(LLWorkerThread::PRIORITY_HIGH | worker->mWorkPriority); worker->mState = LLTextureFetchWorker::LOAD_FROM_SIMULATOR; worker->unlockWorkMutex(); return res; @@ -2734,7 +2721,7 @@ bool LLTextureFetch::receiveImagePacket(const LLHost& host, const LLUUID& id, U1 if ((worker->mState == LLTextureFetchWorker::LOAD_FROM_SIMULATOR) || (worker->mState == LLTextureFetchWorker::LOAD_FROM_NETWORK)) { - worker->setPriority(LLWorkerThread::PRIORITY_HIGH); + worker->setPriority(LLWorkerThread::PRIORITY_HIGH | worker->mWorkPriority); worker->mState = LLTextureFetchWorker::LOAD_FROM_SIMULATOR; } else @@ -2930,6 +2917,35 @@ void LLTextureFetch::cmdDoWork() namespace { + +// Example of a simple notification handler for metrics +// delivery notification. Earlier versions of the code used +// a Responder that tried harder to detect delivery breaks +// but it really isn't that important. If someone wants to +// revisit that effort, here is a place to start. +class AssetReportHandler : public LLCore::HttpHandler +{ +public: + virtual void onCompleted(LLCore::HttpHandle handle, LLCore::HttpResponse * response) + { + LLCore::HttpStatus status(response->getStatus()); + + if (status) + { + LL_WARNS("Texture") << "Successfully delivered asset metrics to grid." + << LL_ENDL; + } + else + { + LL_WARNS("Texture") << "Error delivering asset metrics to grid. Reason: " + << status.toString() << LL_ENDL; + } + } +}; // end class AssetReportHandler + +AssetReportHandler stats_handler; + + /** * Implements the 'Set Region' command. * @@ -2960,73 +2976,9 @@ TFReqSendMetrics::~TFReqSendMetrics() bool TFReqSendMetrics::doWork(LLTextureFetch * fetcher) { - /* - * HTTP POST responder. Doesn't do much but tries to - * detect simple breaks in recording the metrics stream. - * - * The 'volatile' modifiers don't indicate signals, - * mmap'd memory or threads, really. They indicate that - * the referenced data is part of a pseudo-closure for - * this responder rather than being required for correct - * operation. - * - * We don't try very hard with the POST request. We give - * it one shot and that's more-or-less it. With a proper - * refactoring of the LLQueuedThread usage, these POSTs - * could be put in a request object and made more reliable. - */ - class lcl_responder : public LLCurl::Responder - { - public: - lcl_responder(LLTextureFetch * fetcher, - S32 expected_sequence, - volatile const S32 & live_sequence, - volatile bool & reporting_break, - volatile bool & reporting_started) - : LLCurl::Responder(), - mFetcher(fetcher), - mExpectedSequence(expected_sequence), - mLiveSequence(live_sequence), - mReportingBreak(reporting_break), - mReportingStarted(reporting_started) - { - mFetcher->incrCurlPOSTCount(); - } - - ~lcl_responder() - { - mFetcher->decrCurlPOSTCount(); - } - - // virtual - void error(U32 status_num, const std::string & reason) - { - if (mLiveSequence == mExpectedSequence) - { - mReportingBreak = true; - } - LL_WARNS("Texture") << "Break in metrics stream due to POST failure to metrics collection service. Reason: " - << reason << LL_ENDL; - } - - // virtual - void result(const LLSD & content) - { - if (mLiveSequence == mExpectedSequence) - { - mReportingBreak = false; - mReportingStarted = true; - } - } - - private: - LLTextureFetch * mFetcher; - S32 mExpectedSequence; - volatile const S32 & mLiveSequence; - volatile bool & mReportingBreak; - volatile bool & mReportingStarted; - - }; // class lcl_responder + static const U32 report_priority(LLWorkerThread::PRIORITY_LOW); + static const int report_policy_class(LLCore::HttpRequest::DEFAULT_POLICY_ID); + static LLCore::HttpHandler * const handler(fetcher->isQAMode() || true ? &stats_handler : NULL); if (! gViewerAssetStatsThread1) return true; @@ -3054,24 +3006,37 @@ TFReqSendMetrics::doWork(LLTextureFetch * fetcher) // Update sequence number if (S32_MAX == ++report_sequence) report_sequence = 0; - + reporting_started = true; + // Limit the size of the stats report if necessary. merged_llsd["truncated"] = truncate_viewer_metrics(10, merged_llsd); if (! mCapsURL.empty()) { - LLCurlRequest::headers_t headers; -#if 0 - // *FIXME: Going to need a post op after all... - fetcher->getCurlRequest().post(mCapsURL, - headers, - merged_llsd, - new lcl_responder(fetcher, - report_sequence, - report_sequence, - LLTextureFetch::svMetricsDataBreak, - reporting_started)); -#endif + // *FIXME: This mess to get an llsd into a string though + // it's actually no worse than what we currently do... + std::stringstream body; + LLSDSerialize::toXML(merged_llsd, body); + std::string body_str(body.str()); + body.clear(); + + LLCore::HttpHeaders * headers = new LLCore::HttpHeaders; + headers->mHeaders.push_back("Content-Type: application/llsd+xml"); + + LLCore::BufferArray * ba = new LLCore::BufferArray; + ba->append(body_str.c_str(), body_str.length()); + body_str.clear(); + + fetcher->getHttpRequest().requestPost(report_policy_class, + report_priority, + mCapsURL, + ba, + NULL, + headers, + handler); + ba->release(); + headers->release(); + LLTextureFetch::svMetricsDataBreak = false; } else { @@ -3079,7 +3044,7 @@ TFReqSendMetrics::doWork(LLTextureFetch * fetcher) } // In QA mode, Metrics submode, log the result for ease of testing - if (fetcher->isQAMode()) + if (fetcher->isQAMode() || true) { LL_INFOS("Textures") << merged_llsd << LL_ENDL; } diff --git a/indra/newview/lltexturefetch.h b/indra/newview/lltexturefetch.h index 402b198246..cfea3aad9d 100644 --- a/indra/newview/lltexturefetch.h +++ b/indra/newview/lltexturefetch.h @@ -39,7 +39,6 @@ class LLViewerTexture; class LLTextureFetchWorker; -class HTTPGetResponder; class LLTextureCache; class LLImageDecodeThread; class LLHost; @@ -49,7 +48,6 @@ class LLViewerAssetStats; class LLTextureFetch : public LLWorkerThread { friend class LLTextureFetchWorker; - friend class HTTPGetResponder; public: LLTextureFetch(LLTextureCache* cache, LLImageDecodeThread* imagedecodethread, bool threaded, bool qa_mode); @@ -90,8 +88,6 @@ public: LLTextureFetchWorker* getWorker(const LLUUID& id); LLTextureFetchWorker* getWorkerAfterLock(const LLUUID& id); - LLTextureInfo* getTextureInfo() { return &mTextureInfo; } - // Commands available to other threads to control metrics gathering operations. void commandSetRegion(U64 region_handle); void commandSendMetrics(const std::string & caps_url, @@ -104,10 +100,6 @@ public: bool isQAMode() const { return mQAMode; } - // Curl POST counter maintenance - inline void incrCurlPOSTCount() { mCurlPOSTRequestCount++; } - inline void decrCurlPOSTCount() { mCurlPOSTRequestCount--; } - protected: void addToNetworkQueue(LLTextureFetchWorker* worker); void removeFromNetworkQueue(LLTextureFetchWorker* worker, bool cancel); @@ -199,13 +191,6 @@ private: // If true, modifies some behaviors that help with QA tasks. const bool mQAMode; - // Count of POST requests outstanding. We maintain the count - // indirectly in the CURL request responder's ctor and dtor and - // use it when determining whether or not to sleep the thread. Can't - // use the LLCurl module's request counter as it isn't thread compatible. - // *NOTE: Don't mix Atomic and static, apr_initialize must be called first. - LLAtomic32<S32> mCurlPOSTRequestCount; - // Interfaces and objects into the core http library used // to make our HTTP requests. These replace the various // LLCurl interfaces used in the past. |