summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBrad Payne (Vir Linden) <vir@lindenlab.com>2012-11-02 18:07:07 -0400
committerBrad Payne (Vir Linden) <vir@lindenlab.com>2012-11-02 18:07:07 -0400
commit9dd856e37eb9c80701053f0c1a2c0b268f56f5f2 (patch)
tree87216ea11cb8fe5d1d2c2ebd14218f216a475b3c
parentd4dc41dbd5b54501fcb3c94e07e4753ed4196eac (diff)
SH-3429 WIP - Added adaptive retry mechanism for failed appearance update requests
-rwxr-xr-xindra/newview/llappearancemgr.cpp85
-rwxr-xr-xindra/newview/llappearancemgr.h2
-rwxr-xr-x[-rw-r--r--]indra/newview/llcallbacklist.cpp49
-rw-r--r--indra/newview/llcallbacklist.h6
4 files changed, 137 insertions, 5 deletions
diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp
index 51de2fd17b..b2a8a33ecf 100755
--- a/indra/newview/llappearancemgr.cpp
+++ b/indra/newview/llappearancemgr.cpp
@@ -2652,12 +2652,70 @@ void LLAppearanceMgr::updateClothingOrderingInfo(LLUUID cat_id, bool update_base
if (inventory_changed) gInventory.notifyObservers();
}
+// This is intended for use with HTTP Clients/Responders, but is not
+// specifically coupled with those classes.
+class LLHTTPRetryPolicy: public LLThreadSafeRefCount
+{
+public:
+ LLHTTPRetryPolicy() {}
+ virtual ~LLHTTPRetryPolicy() {}
+ virtual bool shouldRetry(U32 status, F32& seconds_to_wait) = 0;
+};
+
+// Example of simplest possible policy, not necessarily recommended.
+class LLAlwaysRetryImmediatelyPolicy: public LLHTTPRetryPolicy
+{
+public:
+ LLAlwaysRetryImmediatelyPolicy() {}
+ bool shouldRetry(U32 status, F32& seconds_to_wait)
+ {
+ seconds_to_wait = 0.0;
+ return true;
+ }
+};
+
+// Very general policy with geometric back-off after failures,
+// up to a maximum delay, and maximum number of retries.
+class LLAdaptiveRetryPolicy: public LLHTTPRetryPolicy
+{
+public:
+ LLAdaptiveRetryPolicy(F32 min_delay, F32 max_delay, F32 backoff_factor, U32 max_retries):
+ mMinDelay(min_delay),
+ mMaxDelay(max_delay),
+ mBackoffFactor(backoff_factor),
+ mMaxRetries(max_retries),
+ mDelay(min_delay),
+ mRetryCount(0)
+ {
+ }
+
+ bool shouldRetry(U32 status, F32& seconds_to_wait)
+ {
+ seconds_to_wait = mDelay;
+ mDelay = llclamp(mDelay*mBackoffFactor,mMinDelay,mMaxDelay);
+ mRetryCount++;
+ return (mRetryCount<=mMaxRetries);
+ }
+
+private:
+ F32 mMinDelay; // delay never less than this value
+ F32 mMaxDelay; // delay never exceeds this value
+ F32 mBackoffFactor; // delay increases by this factor after each retry, up to mMaxDelay.
+ U32 mMaxRetries; // maximum number of times shouldRetry will return true.
+ F32 mDelay; // current delay.
+ U32 mRetryCount; // number of times shouldRetry has been called.
+};
+
class RequestAgentUpdateAppearanceResponder: public LLHTTPClient::Responder
{
public:
RequestAgentUpdateAppearanceResponder()
{
- llinfos << "request created" << llendl;
+ mRetryPolicy = new LLAdaptiveRetryPolicy(1.0, 16.0, 2.0, 5);
+ }
+
+ virtual ~RequestAgentUpdateAppearanceResponder()
+ {
}
// Successful completion.
@@ -2669,11 +2727,25 @@ public:
// Error
/*virtual*/ void error(U32 status, const std::string& reason)
{
- llwarns << "appearance update request failed, reason: " << reason << llendl;
+ llwarns << "appearance update request failed, status: " << status << " reason: " << reason << llendl;
+ F32 seconds_to_wait;
+ if (mRetryPolicy->shouldRetry(status,seconds_to_wait))
+ {
+ doAfterInterval(boost::bind(&LLAppearanceMgr::requestServerAppearanceUpdate,
+ LLAppearanceMgr::getInstance(),
+ LLCurl::ResponderPtr(this)),
+ seconds_to_wait);
+ }
+ else
+ {
+ llwarns << "giving up after too many retries" << llendl;
+ }
}
+
+ LLPointer<LLHTTPRetryPolicy> mRetryPolicy;
};
-void LLAppearanceMgr::requestServerAppearanceUpdate()
+void LLAppearanceMgr::requestServerAppearanceUpdate(LLCurl::ResponderPtr responder_ptr)
{
if (!gAgent.getRegion())
{
@@ -2693,7 +2765,12 @@ void LLAppearanceMgr::requestServerAppearanceUpdate()
LLSD body;
S32 cof_version = getCOFVersion();
body["cof_version"] = cof_version;
- LLHTTPClient::post(url, body, new RequestAgentUpdateAppearanceResponder);
+ //LLCurl::ResponderPtr responder_ptr;
+ if (!responder_ptr.get())
+ {
+ responder_ptr = new RequestAgentUpdateAppearanceResponder;
+ }
+ LLHTTPClient::post(url, body, responder_ptr);
llassert(cof_version >= mLastUpdateRequestCOFVersion);
mLastUpdateRequestCOFVersion = cof_version;
}
diff --git a/indra/newview/llappearancemgr.h b/indra/newview/llappearancemgr.h
index 4baee10218..01ed66711c 100755
--- a/indra/newview/llappearancemgr.h
+++ b/indra/newview/llappearancemgr.h
@@ -187,7 +187,7 @@ public:
bool isInUpdateAppearanceFromCOF() { return mIsInUpdateAppearanceFromCOF; }
- void requestServerAppearanceUpdate();
+ void requestServerAppearanceUpdate(LLCurl::ResponderPtr responder_ptr = NULL);
protected:
LLAppearanceMgr();
diff --git a/indra/newview/llcallbacklist.cpp b/indra/newview/llcallbacklist.cpp
index 357a6582d1..79ec43dfe9 100644..100755
--- a/indra/newview/llcallbacklist.cpp
+++ b/indra/newview/llcallbacklist.cpp
@@ -27,6 +27,7 @@
#include "llviewerprecompiledheaders.h"
#include "llcallbacklist.h"
+#include "lleventtimer.h"
// Library includes
#include "llerror.h"
@@ -180,6 +181,54 @@ void doOnIdleRepeating(bool_func_t callable)
gIdleCallbacks.addFunction(&OnIdleCallbackRepeating::onIdle,cb_functor);
}
+class NullaryFuncEventTimer: public LLEventTimer
+{
+public:
+ NullaryFuncEventTimer(nullary_func_t callable, F32 seconds):
+ LLEventTimer(seconds),
+ mCallable(callable)
+ {
+ }
+
+private:
+ BOOL tick()
+ {
+ mCallable();
+ return TRUE;
+ }
+
+ nullary_func_t mCallable;
+};
+
+// Call a given callable once after specified interval.
+void doAfterInterval(nullary_func_t callable, F32 seconds)
+{
+ new NullaryFuncEventTimer(callable, seconds);
+}
+
+class BoolFuncEventTimer: public LLEventTimer
+{
+public:
+ BoolFuncEventTimer(bool_func_t callable, F32 seconds):
+ LLEventTimer(seconds),
+ mCallable(callable)
+ {
+ }
+private:
+ BOOL tick()
+ {
+ return mCallable();
+ }
+
+ bool_func_t mCallable;
+};
+
+// Call a given callable every specified number of seconds, until it returns true.
+void doPeriodically(bool_func_t callable, F32 seconds)
+{
+ new BoolFuncEventTimer(callable, seconds);
+}
+
#ifdef _DEBUG
void test1(void *data)
diff --git a/indra/newview/llcallbacklist.h b/indra/newview/llcallbacklist.h
index 97f3bfd9ee..0516c9cdb4 100644
--- a/indra/newview/llcallbacklist.h
+++ b/indra/newview/llcallbacklist.h
@@ -61,6 +61,12 @@ void doOnIdleOneTime(nullary_func_t callable);
// Repeatedly call a callable in idle loop until it returns true.
void doOnIdleRepeating(bool_func_t callable);
+// Call a given callable once after specified interval.
+void doAfterInterval(nullary_func_t callable, F32 seconds);
+
+// Call a given callable every specified number of seconds, until it returns true.
+void doPeriodically(bool_func_t callable, F32 seconds);
+
extern LLCallbackList gIdleCallbacks;
#endif