summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMonty Brandenberg <monty@lindenlab.com>2012-06-01 14:07:34 -0400
committerMonty Brandenberg <monty@lindenlab.com>2012-06-01 14:07:34 -0400
commitb8edacd0bb4feacc3ac1d61421e600c75ab87f7c (patch)
tree8f0e359445e324e4694e79526e443d5e6c90fab4
parent8fc350125c671baeae6b7f8b1814251009f4f50a (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.
-rw-r--r--indra/llcorehttp/CMakeLists.txt27
-rw-r--r--indra/llcorehttp/_assert.h39
-rw-r--r--indra/llcorehttp/_httplibcurl.cpp52
-rw-r--r--indra/llcorehttp/_httplibcurl.h27
-rw-r--r--indra/llcorehttp/_httpopcancel.h2
-rw-r--r--indra/llcorehttp/_httpoperation.cpp8
-rw-r--r--indra/llcorehttp/_httpoperation.h42
-rw-r--r--indra/llcorehttp/_httpoprequest.cpp113
-rw-r--r--indra/llcorehttp/_httpoprequest.h11
-rw-r--r--indra/llcorehttp/_httpopsetpriority.cpp77
-rw-r--r--indra/llcorehttp/_httpopsetpriority.h70
-rw-r--r--indra/llcorehttp/_httppolicy.cpp97
-rw-r--r--indra/llcorehttp/_httppolicy.h28
-rw-r--r--indra/llcorehttp/_httpreadyqueue.h85
-rw-r--r--indra/llcorehttp/_httprequestqueue.cpp2
-rw-r--r--indra/llcorehttp/_httpservice.cpp63
-rw-r--r--indra/llcorehttp/_httpservice.h26
-rw-r--r--indra/llcorehttp/_refcounted.h14
-rw-r--r--indra/llcorehttp/httpcommon.cpp15
-rw-r--r--indra/llcorehttp/httpcommon.h8
-rw-r--r--indra/llcorehttp/httprequest.cpp52
-rw-r--r--indra/llcorehttp/httprequest.h49
-rw-r--r--indra/llcorehttp/tests/test_httprequest.hpp2
-rw-r--r--indra/newview/lltexturefetch.cpp235
-rw-r--r--indra/newview/lltexturefetch.h15
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.