summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJames Cook <james@lindenlab.com>2010-04-23 15:11:33 -0700
committerJames Cook <james@lindenlab.com>2010-04-23 15:11:33 -0700
commitc1ff7147974a031643776d8ea950f1bc1466737c (patch)
tree8978a8d984f3fd2519144acdeb34c1ecd276bc64
parentdd8f16b15b07d39a1aa1fb53bf6bae1dfdfb56c3 (diff)
DEV-47529 Name cache can handle People API 503 service unavailable
It caches a dummy name "???" for a while and retries - soon for 503, longer delay for other errors. Reviewed with Simon.
-rw-r--r--indra/llmessage/llavatarnamecache.cpp116
1 files changed, 89 insertions, 27 deletions
diff --git a/indra/llmessage/llavatarnamecache.cpp b/indra/llmessage/llavatarnamecache.cpp
index 72498111fd..eabd311bb0 100644
--- a/indra/llmessage/llavatarnamecache.cpp
+++ b/indra/llmessage/llavatarnamecache.cpp
@@ -81,7 +81,9 @@ namespace LLAvatarNameCache
// Periodically clean out expired entries from the cache
LLFrameTimer sEraseExpiredTimer;
- void processNameFromService(const LLSD& row);
+ // Handle name response off network
+ void processName(const LLUUID& agent_id, const LLAvatarName& av_name);
+
void requestNamesViaCapability();
void requestNamesViaLegacy();
bool isRequestPending(const LLUUID& agent_id);
@@ -147,42 +149,102 @@ public:
LLSD::array_const_iterator it = agents.beginArray();
for ( ; it != agents.endArray(); ++it)
{
- const LLSD& entry = *it;
- LLAvatarNameCache::processNameFromService(entry);
+ const LLSD& row = *it;
+ LLUUID agent_id = row["id"].asUUID();
+
+ LLAvatarName av_name;
+ av_name.fromLLSD(row);
+
+ // Some avatars don't have explicit display names set
+ if (av_name.mDisplayName.empty())
+ {
+ av_name.mDisplayName = av_name.mSLID;
+ }
+
+ LLAvatarNameCache::processName(agent_id, av_name);
}
}
- /*virtual*/ void error(U32 status, const std::string& reason)
+ // This is called for both successful and failed requests, and is
+ // called _after_ result() above.
+ /*virtual*/ void completedHeader(U32 status, const std::string& reason,
+ const LLSD& headers)
{
- llinfos << "LLAvatarNameResponder error " << status << " " << reason << llendl;
+ // Only care about headers when there is an error
+ if (isGoodStatus(status)) return;
+
+ // We're going to construct a dummy record and cache it for a while,
+ // either briefly for a 503 Service Unavailable, or longer for other
+ // errors.
+ F64 retry_timestamp = errorRetryTimestamp(status, headers);
+
+ // *NOTE: "??" starts trigraphs in C/C++, escape the question marks.
+ const std::string DUMMY_NAME("\?\?\?");
+ LLAvatarName av_name;
+ av_name.mSLID = DUMMY_NAME;
+ av_name.mDisplayName = DUMMY_NAME;
+ av_name.mIsDisplayNameDefault = false;
+ av_name.mExpires = retry_timestamp;
+
+ // Add dummy records for all agent IDs in this request
+ std::vector<LLUUID>::const_iterator it = mAgentIDs.begin();
+ for ( ; it != mAgentIDs.end(); ++it)
+ {
+ const LLUUID& agent_id = *it;
+ LLAvatarNameCache::processName(agent_id, av_name);
+ }
}
-};
-
-// "expires" is seconds-from-epoch
-void LLAvatarNameCache::processNameFromService(const LLSD& row)
-{
- LLAvatarName av_name;
- av_name.mSLID = row["sl_id"].asString();
- av_name.mDisplayName = row["display_name"].asString();
- av_name.mIsDisplayNameDefault = row["is_display_name_default"].asBoolean();
- av_name.mExpires = row["display_name_expires"].asReal();
- llinfos << "JAMESDEBUG expires " << av_name.mExpires << " now " << LLFrameTimer::getTotalSeconds() << llendl;
+ // Return time to retry a request that generated an error, based on
+ // error type and headers. Return value is seconds-since-epoch.
+ F64 errorRetryTimestamp(S32 status, const LLSD& headers)
+ {
+ LLSD expires = headers["expires"];
+ if (expires.isDefined())
+ {
+ LLDate expires_date = expires.asDate();
+ return expires_date.secondsSinceEpoch();
+ }
- // HACK for pretty stars
- //if (row["last_name"].asString() == "Linden")
- //{
- // av_name.mBadge = "Person_Star";
- //}
+ LLSD retry_after = headers["retry-after"];
+ if (retry_after.isDefined())
+ {
+ // does the header use the delta-seconds type?
+ S32 delta_seconds = retry_after.asInteger();
+ if (delta_seconds > 0)
+ {
+ // ...valid delta-seconds
+ F64 now = LLFrameTimer::getTotalSeconds();
+ return now + F64(delta_seconds);
+ }
+ else
+ {
+ // ...it's a date
+ LLDate expires_date = retry_after.asDate();
+ return expires_date.secondsSinceEpoch();
+ }
+ }
- // Some avatars don't have explicit display names set
- if (av_name.mDisplayName.empty())
- {
- av_name.mDisplayName = av_name.mSLID;
+ // No information in header, make a guess
+ F64 now = LLFrameTimer::getTotalSeconds();
+ if (status == 503)
+ {
+ // ...service unavailable, retry soon
+ const F64 SERVICE_UNAVAILABLE_DELAY = 600.0; // 10 min
+ return now + SERVICE_UNAVAILABLE_DELAY;
+ }
+ else
+ {
+ // ...other unexpected error
+ const F64 DEFAULT_DELAY = 3600.0; // 1 hour
+ return now + DEFAULT_DELAY;
+ }
}
+};
- // add to cache
- LLUUID agent_id = row["id"].asUUID();
+void LLAvatarNameCache::processName(const LLUUID& agent_id,
+ const LLAvatarName& av_name)
+{
sCache[agent_id] = av_name;
sPendingQueue.erase(agent_id);