summaryrefslogtreecommitdiff
path: root/indra/newview/llappcorehttp.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'indra/newview/llappcorehttp.cpp')
-rwxr-xr-x[-rw-r--r--]indra/newview/llappcorehttp.cpp352
1 files changed, 312 insertions, 40 deletions
diff --git a/indra/newview/llappcorehttp.cpp b/indra/newview/llappcorehttp.cpp
index 0d7d41304d..f5f224b83e 100644..100755
--- a/indra/newview/llappcorehttp.cpp
+++ b/indra/newview/llappcorehttp.cpp
@@ -4,7 +4,7 @@
*
* $LicenseInfo:firstyear=2012&license=viewerlgpl$
* Second Life Viewer Source Code
- * Copyright (C) 2012, Linden Research, Inc.
+ * Copyright (C) 2012-2014, 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
@@ -28,17 +28,90 @@
#include "llappcorehttp.h"
+#include "llappviewer.h"
#include "llviewercontrol.h"
+// Here is where we begin to get our connection usage under control.
+// This establishes llcorehttp policy classes that, among other
+// things, limit the maximum number of connections to outside
+// services. Each of the entries below maps to a policy class and
+// has a limit, sometimes configurable, of how many connections can
+// be open at a time.
+
const F64 LLAppCoreHttp::MAX_THREAD_WAIT_TIME(10.0);
+const long LLAppCoreHttp::PIPELINING_DEPTH(5L);
+
+// Default and dynamic values for classes
+static const struct
+{
+ U32 mDefault;
+ U32 mMin;
+ U32 mMax;
+ U32 mRate;
+ bool mPipelined;
+ std::string mKey;
+ const char * mUsage;
+} init_data[LLAppCoreHttp::AP_COUNT] =
+{
+ { // AP_DEFAULT
+ 8, 8, 8, 0, false,
+ "",
+ "other"
+ },
+ { // AP_TEXTURE
+ 8, 1, 12, 0, true,
+ "TextureFetchConcurrency",
+ "texture fetch"
+ },
+ { // AP_MESH1
+ 32, 1, 128, 0, false,
+ "MeshMaxConcurrentRequests",
+ "mesh fetch"
+ },
+ { // AP_MESH2
+ 8, 1, 32, 0, true,
+ "Mesh2MaxConcurrentRequests",
+ "mesh2 fetch"
+ },
+ { // AP_LARGE_MESH
+ 2, 1, 8, 0, false,
+ "",
+ "large mesh fetch"
+ },
+ { // AP_UPLOADS
+ 2, 1, 8, 0, false,
+ "",
+ "asset upload"
+ },
+ { // AP_LONG_POLL
+ 32, 32, 32, 0, false,
+ "",
+ "long poll"
+ },
+ { // AP_INVENTORY
+ 4, 1, 4, 0, false,
+ "",
+ "inventory"
+ }
+};
+
+static void setting_changed();
+
+
+LLAppCoreHttp::HttpClass::HttpClass()
+ : mPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID),
+ mConnLimit(0U),
+ mPipelined(false)
+{}
+
LLAppCoreHttp::LLAppCoreHttp()
: mRequest(NULL),
mStopHandle(LLCORE_HTTP_HANDLE_INVALID),
mStopRequested(0.0),
mStopped(false),
- mPolicyDefault(-1)
+ mPipelined(true)
{}
@@ -54,30 +127,28 @@ void LLAppCoreHttp::init()
LLCore::HttpStatus status = LLCore::HttpRequest::createService();
if (! status)
{
- LL_ERRS("Init") << "Failed to initialize HTTP services. Reason: "
- << status.toString()
+ LL_ERRS("Init") << "Failed to initialize HTTP services. Reason: " << status.toString()
<< LL_ENDL;
}
// Point to our certs or SSH/https: will fail on connect
- status = LLCore::HttpRequest::setPolicyGlobalOption(LLCore::HttpRequest::GP_CA_FILE,
- gDirUtilp->getCAFile());
+ status = LLCore::HttpRequest::setStaticPolicyOption(LLCore::HttpRequest::PO_CA_FILE,
+ LLCore::HttpRequest::GLOBAL_POLICY_ID,
+ gDirUtilp->getCAFile(), NULL);
if (! status)
{
- LL_ERRS("Init") << "Failed to set CA File for HTTP services. Reason: "
- << status.toString()
+ LL_ERRS("Init") << "Failed to set CA File for HTTP services. Reason: " << status.toString()
<< LL_ENDL;
}
- // Establish HTTP Proxy. "LLProxy" is a special string which directs
- // the code to use LLProxy::applyProxySettings() to establish any
- // HTTP or SOCKS proxy for http operations.
- status = LLCore::HttpRequest::setPolicyGlobalOption(LLCore::HttpRequest::GP_LLPROXY, 1);
+ // Establish HTTP Proxy, if desired.
+ status = LLCore::HttpRequest::setStaticPolicyOption(LLCore::HttpRequest::PO_LLPROXY,
+ LLCore::HttpRequest::GLOBAL_POLICY_ID,
+ 1, NULL);
if (! status)
{
- LL_ERRS("Init") << "Failed to set HTTP proxy for HTTP services. Reason: "
- << status.toString()
- << LL_ENDL;
+ LL_WARNS("Init") << "Failed to set HTTP proxy for HTTP services. Reason: " << status.toString()
+ << LL_ENDL;
}
// Tracing levels for library & libcurl (note that 2 & 3 are beyond spammy):
@@ -90,47 +161,93 @@ void LLAppCoreHttp::init()
{
long trace_level(0L);
trace_level = long(gSavedSettings.getU32(http_trace));
- status = LLCore::HttpRequest::setPolicyGlobalOption(LLCore::HttpRequest::GP_TRACE, trace_level);
+ status = LLCore::HttpRequest::setStaticPolicyOption(LLCore::HttpRequest::PO_TRACE,
+ LLCore::HttpRequest::GLOBAL_POLICY_ID,
+ trace_level, NULL);
}
// Setup default policy and constrain if directed to
- mPolicyDefault = LLCore::HttpRequest::DEFAULT_POLICY_ID;
- static const std::string texture_concur("TextureFetchConcurrency");
- if (gSavedSettings.controlExists(texture_concur))
+ mHttpClasses[AP_DEFAULT].mPolicy = LLCore::HttpRequest::DEFAULT_POLICY_ID;
+
+ // Setup additional policies based on table and some special rules
+ llassert(LL_ARRAY_SIZE(init_data) == AP_COUNT);
+ for (int i(0); i < LL_ARRAY_SIZE(init_data); ++i)
{
- U32 concur(llmin(gSavedSettings.getU32(texture_concur), U32(12)));
+ const EAppPolicy app_policy(static_cast<EAppPolicy>(i));
- if (concur > 0)
+ if (AP_DEFAULT == app_policy)
{
- LLCore::HttpStatus status;
- status = LLCore::HttpRequest::setPolicyClassOption(mPolicyDefault,
- LLCore::HttpRequest::CP_CONNECTION_LIMIT,
- concur);
- if (! status)
- {
- LL_WARNS("Init") << "Unable to set texture fetch concurrency. Reason: "
- << status.toString()
- << LL_ENDL;
- }
- else
- {
- LL_INFOS("Init") << "Application settings overriding default texture fetch concurrency. New value: "
- << concur
- << LL_ENDL;
- }
+ // Pre-created
+ continue;
+ }
+
+ mHttpClasses[app_policy].mPolicy = LLCore::HttpRequest::createPolicyClass();
+ if (! mHttpClasses[app_policy].mPolicy)
+ {
+ // Use default policy (but don't accidentally modify default)
+ LL_WARNS("Init") << "Failed to create HTTP policy class for " << init_data[i].mUsage
+ << ". Using default policy."
+ << LL_ENDL;
+ mHttpClasses[app_policy].mPolicy = mHttpClasses[AP_DEFAULT].mPolicy;
+ continue;
}
}
+
+ // Need a request object to handle dynamic options before setting them
+ mRequest = new LLCore::HttpRequest;
+
+ // Apply initial settings
+ refreshSettings(true);
// Kick the thread
status = LLCore::HttpRequest::startThread();
if (! status)
{
- LL_ERRS("Init") << "Failed to start HTTP servicing thread. Reason: "
- << status.toString()
+ LL_ERRS("Init") << "Failed to start HTTP servicing thread. Reason: " << status.toString()
<< LL_ENDL;
}
- mRequest = new LLCore::HttpRequest;
+ // Signal for global pipelining preference from settings
+ static const std::string http_pipelining("HttpPipelining");
+ if (gSavedSettings.controlExists(http_pipelining))
+ {
+ LLPointer<LLControlVariable> cntrl_ptr = gSavedSettings.getControl(http_pipelining);
+ if (cntrl_ptr.isNull())
+ {
+ LL_WARNS("Init") << "Unable to set signal on global setting '" << http_pipelining
+ << "'" << LL_ENDL;
+ }
+ else
+ {
+ mPipelinedSignal = cntrl_ptr->getCommitSignal()->connect(boost::bind(&setting_changed));
+ }
+ }
+
+ // Register signals for settings and state changes
+ for (int i(0); i < LL_ARRAY_SIZE(init_data); ++i)
+ {
+ const EAppPolicy app_policy(static_cast<EAppPolicy>(i));
+
+ if (! init_data[i].mKey.empty() && gSavedSettings.controlExists(init_data[i].mKey))
+ {
+ LLPointer<LLControlVariable> cntrl_ptr = gSavedSettings.getControl(init_data[i].mKey);
+ if (cntrl_ptr.isNull())
+ {
+ LL_WARNS("Init") << "Unable to set signal on global setting '" << init_data[i].mKey
+ << "'" << LL_ENDL;
+ }
+ else
+ {
+ mHttpClasses[app_policy].mSettingsSignal = cntrl_ptr->getCommitSignal()->connect(boost::bind(&setting_changed));
+ }
+ }
+ }
+}
+
+
+void setting_changed()
+{
+ LLAppViewer::instance()->getAppCoreHttp().refreshSettings(false);
}
@@ -173,6 +290,12 @@ void LLAppCoreHttp::cleanup()
}
}
+ for (int i(0); i < LL_ARRAY_SIZE(mHttpClasses); ++i)
+ {
+ mHttpClasses[i].mSettingsSignal.disconnect();
+ }
+ mPipelinedSignal.disconnect();
+
delete mRequest;
mRequest = NULL;
@@ -186,6 +309,155 @@ void LLAppCoreHttp::cleanup()
}
+void LLAppCoreHttp::refreshSettings(bool initial)
+{
+ LLCore::HttpStatus status;
+
+ // Global pipelining setting
+ bool pipeline_changed(false);
+ static const std::string http_pipelining("HttpPipelining");
+ if (gSavedSettings.controlExists(http_pipelining))
+ {
+ // Default to true (in ctor) if absent.
+ bool pipelined(gSavedSettings.getBOOL(http_pipelining));
+ if (pipelined != mPipelined)
+ {
+ mPipelined = pipelined;
+ pipeline_changed = true;
+ }
+ }
+
+ for (int i(0); i < LL_ARRAY_SIZE(init_data); ++i)
+ {
+ const EAppPolicy app_policy(static_cast<EAppPolicy>(i));
+
+ if (initial)
+ {
+ // Init-time only settings, can use the static setters here
+
+ if (init_data[i].mRate)
+ {
+ // Set any desired throttle
+ status = LLCore::HttpRequest::setStaticPolicyOption(LLCore::HttpRequest::PO_THROTTLE_RATE,
+ mHttpClasses[app_policy].mPolicy,
+ init_data[i].mRate,
+ NULL);
+ if (! status)
+ {
+ LL_WARNS("Init") << "Unable to set " << init_data[i].mUsage
+ << " throttle rate. Reason: " << status.toString()
+ << LL_ENDL;
+ }
+ }
+
+ }
+
+ // Init- or run-time settings. Must use the queued request API.
+
+ // Pipelining changes
+ if (initial || pipeline_changed)
+ {
+ const bool to_pipeline(mPipelined && init_data[i].mPipelined);
+ if (to_pipeline != mHttpClasses[app_policy].mPipelined)
+ {
+ // Pipeline election changing, set dynamic option via request
+
+ LLCore::HttpHandle handle;
+ const long new_depth(to_pipeline ? PIPELINING_DEPTH : 0);
+
+ handle = mRequest->setPolicyOption(LLCore::HttpRequest::PO_PIPELINING_DEPTH,
+ mHttpClasses[app_policy].mPolicy,
+ new_depth,
+ NULL);
+ if (LLCORE_HTTP_HANDLE_INVALID == handle)
+ {
+ status = mRequest->getStatus();
+ LL_WARNS("Init") << "Unable to set " << init_data[i].mUsage
+ << " pipelining. Reason: " << status.toString()
+ << LL_ENDL;
+ }
+ else
+ {
+ LL_DEBUGS("Init") << "Changed " << init_data[i].mUsage
+ << " pipelining. New value: " << new_depth
+ << LL_ENDL;
+ mHttpClasses[app_policy].mPipelined = to_pipeline;
+ }
+ }
+ }
+
+ // Get target connection concurrency value
+ U32 setting(init_data[i].mDefault);
+ if (! init_data[i].mKey.empty() && gSavedSettings.controlExists(init_data[i].mKey))
+ {
+ U32 new_setting(gSavedSettings.getU32(init_data[i].mKey));
+ if (new_setting)
+ {
+ // Treat zero settings as an ask for default
+ setting = llclamp(new_setting, init_data[i].mMin, init_data[i].mMax);
+ }
+ }
+
+ if (initial || setting != mHttpClasses[app_policy].mConnLimit || pipeline_changed)
+ {
+ // Set it and report. Strategies depend on pipelining:
+ //
+ // No Pipelining. Llcorehttp manages connections itself based
+ // on the PO_CONNECTION_LIMIT setting. Set both limits to the
+ // same value for logical consistency. In the future, may
+ // hand over connection management to libcurl after the
+ // connection cache has been better vetted.
+ //
+ // Pipelining. Libcurl is allowed to manage connections to a
+ // great degree. Steady state will connection limit based on
+ // the per-host setting. Transitions (region crossings, new
+ // avatars, etc.) can request additional outbound connections
+ // to other servers via 2X total connection limit.
+ //
+ LLCore::HttpHandle handle;
+ handle = mRequest->setPolicyOption(LLCore::HttpRequest::PO_CONNECTION_LIMIT,
+ mHttpClasses[app_policy].mPolicy,
+ (mHttpClasses[app_policy].mPipelined ? 2 * setting : setting),
+ NULL);
+ if (LLCORE_HTTP_HANDLE_INVALID == handle)
+ {
+ status = mRequest->getStatus();
+ LL_WARNS("Init") << "Unable to set " << init_data[i].mUsage
+ << " concurrency. Reason: " << status.toString()
+ << LL_ENDL;
+ }
+ else
+ {
+ handle = mRequest->setPolicyOption(LLCore::HttpRequest::PO_PER_HOST_CONNECTION_LIMIT,
+ mHttpClasses[app_policy].mPolicy,
+ setting,
+ NULL);
+ if (LLCORE_HTTP_HANDLE_INVALID == handle)
+ {
+ status = mRequest->getStatus();
+ LL_WARNS("Init") << "Unable to set " << init_data[i].mUsage
+ << " per-host concurrency. Reason: " << status.toString()
+ << LL_ENDL;
+ }
+ else
+ {
+ LL_DEBUGS("Init") << "Changed " << init_data[i].mUsage
+ << " concurrency. New value: " << setting
+ << LL_ENDL;
+ mHttpClasses[app_policy].mConnLimit = setting;
+ if (initial && setting != init_data[i].mDefault)
+ {
+ LL_INFOS("Init") << "Application settings overriding default " << init_data[i].mUsage
+ << " concurrency. New value: " << setting
+ << LL_ENDL;
+ }
+ }
+ }
+ }
+ }
+}
+
+
void LLAppCoreHttp::onCompleted(LLCore::HttpHandle, LLCore::HttpResponse *)
{
mStopped = true;