From 2cde962d5db94baf860eb94fecaf9671548b2c53 Mon Sep 17 00:00:00 2001 From: "dolphin@dolphin-THINK.lindenlab.com" Date: Mon, 19 Nov 2012 08:06:42 -0800 Subject: Test populating the experience keys UI with avatar name data. --- indra/llmessage/llexperiencecache.cpp | 138 +++++++++++++++++++++++++++++++--- 1 file changed, 128 insertions(+), 10 deletions(-) (limited to 'indra/llmessage/llexperiencecache.cpp') diff --git a/indra/llmessage/llexperiencecache.cpp b/indra/llmessage/llexperiencecache.cpp index 8667ae8981..0d8f76c7e2 100644 --- a/indra/llmessage/llexperiencecache.cpp +++ b/indra/llmessage/llexperiencecache.cpp @@ -25,24 +25,20 @@ */ #include "linden_common.h" +#include "llavatarname.h" #include "llframetimer.h" #include "llhttpclient.h" +#include "llsdserialize.h" #include #include #include "llexperiencecache.h" -class LLExperienceData -{ -public: - std::string mDisplayName; -}; - namespace LLExperienceCache { - bool sRunning = true; + bool sRunning = false; std::string sLookupURL; typedef std::set ask_queue_t; @@ -52,19 +48,122 @@ namespace LLExperienceCache pending_queue_t sPendingQueue; - typedef std::map cache_t; cache_t sCache; LLFrameTimer sRequestTimer; + + void processExperience( const LLUUID& agent_id, const LLExperienceData& experience, bool add_to_cache ) + { + if(add_to_cache) + { + sCache[agent_id]=experience; + + sPendingQueue.erase(agent_id); + + + //signal + } + } + + void initClass( bool running ) + { + sRunning = false; + } + + const cache_t& getCached() + { + return sCache; + } + + + + void importFile(std::istream& istr) + { + LLSD data; + S32 parse_count = LLSDSerialize::fromXMLDocument(data, istr); + if(parse_count < 1) return; + + LLSD agents = data["agents"]; + + LLUUID agent_id; + LLExperienceData experience; + LLSD::map_const_iterator it = agents.beginMap(); + for(; it != agents.endMap() ; ++it) + { + agent_id.set(it->first); + experience.fromLLSD( it->second); + sCache[agent_id]=experience; + } + + LL_INFOS("ExperienceCache") << "loaded " << sCache.size() << LL_ENDL; + } + + void exportFile(std::ostream& ostr) + { + LLSD agents; + + cache_t::const_iterator it =sCache.begin(); + for( ; it != sCache.end() ; ++it) + { + agents[it->first.asString()] = it->second.asLLSD(); + } + + LLSD data; + data["agents"] = agents; + + LLSDSerialize::toPrettyXML(data, ostr); + } + class LLExperienceResponder : public LLHTTPClient::Responder { public: - LLExperienceResponder(std::vector agent_ids) + LLExperienceResponder(const std::vector& agent_ids) + :mAgentIds(agent_ids) { } + + virtual void completedHeader(U32 status, const std::string& reason, const LLSD& content) + { + mHeaders = content; + } + + virtual void result(const LLSD& content) + { + LLSD agents = content["agents"]; + LLSD::array_const_iterator it = agents.beginArray(); + for( /**/ ; it != agents.endArray(); ++it) + { + const LLSD& row = *it; + LLUUID agent_id = row["id"].asUUID(); + + LLExperienceData experience; + + if(experience.fromLLSD(row)) + { + LL_DEBUGS("ExperienceCache") << __FUNCTION__ << "Received result for " << agent_id + << "display '" << experience.mDisplayName << "'" << LL_ENDL ; + + processExperience(agent_id, experience, true); + } + } + + LLSD unresolved_agents = content["bad_ids"]; + S32 num_unresolved = unresolved_agents.size(); + if(num_unresolved > 0) + { + LL_DEBUGS("ExperienceCache") << __FUNCTION__ << "Ignoreing " << num_unresolved + << " bad ids" << LL_ENDL ; + } + + LL_DEBUGS("ExperienceCache") << __FUNCTION__ << sCache.size() << " cached experiences" << LL_ENDL; + } + + private: + std::vector mAgentIds; + LLSD mHeaders; }; void requestExperiences() @@ -171,7 +270,7 @@ namespace LLExperienceCache bool get( const LLUUID& agent_id, LLExperienceData* experience_data ) { - if(!sRunning) + if(sRunning) { cache_t::const_iterator it = sCache.find(agent_id); @@ -193,3 +292,22 @@ namespace LLExperienceCache } + +bool LLExperienceData::fromLLSD( const LLSD& sd ) +{ + mDisplayName = sd["display_name"].asString(); + mDescription = sd["username"].asString(); + + if(mDisplayName.empty() || mDescription.empty()) return false; + + mDescription += " % Hey, this is a description!"; + return true; +} + +LLSD LLExperienceData::asLLSD() const +{ + LLSD sd; + sd["display_name"] = mDisplayName; + sd["username"] = mDescription.substr(0, llmin(mDescription.size(),mDescription.find(" %"))); + return sd; +} -- cgit v1.2.3 From 2566e0d08fd7e8a47fc690a8163c1273d91141c2 Mon Sep 17 00:00:00 2001 From: "dolphin@dolphin-THINK.lindenlab.com" Date: Mon, 26 Nov 2012 08:42:23 -0800 Subject: Added code for simulator integration. Added signals for cache update callbacks. Added expiration timers for cached experiences. --- indra/llmessage/llexperiencecache.cpp | 290 ++++++++++++++++++++++++++++++---- 1 file changed, 263 insertions(+), 27 deletions(-) (limited to 'indra/llmessage/llexperiencecache.cpp') diff --git a/indra/llmessage/llexperiencecache.cpp b/indra/llmessage/llexperiencecache.cpp index 0d8f76c7e2..562c4c40df 100644 --- a/indra/llmessage/llexperiencecache.cpp +++ b/indra/llmessage/llexperiencecache.cpp @@ -31,6 +31,7 @@ #include "llsdserialize.h" #include #include +#include "boost\tokenizer.hpp" #include "llexperiencecache.h" @@ -38,7 +39,6 @@ namespace LLExperienceCache { - bool sRunning = false; std::string sLookupURL; typedef std::set ask_queue_t; @@ -47,29 +47,45 @@ namespace LLExperienceCache typedef std::map pending_queue_t; pending_queue_t sPendingQueue; - cache_t sCache; + int sMaximumLookups = 10; LLFrameTimer sRequestTimer; + // Periodically clean out expired entries from the cache + LLFrameTimer sEraseExpiredTimer; + + // May have multiple callbacks for a single ID, which are + // represented as multiple slots bound to the signal. + // Avoid copying signals via pointers. + typedef std::map signal_map_t; + signal_map_t sSignalMap; + + bool max_age_from_cache_control(const std::string& cache_control, S32 *max_age); + void eraseExpired(); - void processExperience( const LLUUID& agent_id, const LLExperienceData& experience, bool add_to_cache ) + void processExperience( const LLUUID& agent_id, const LLExperienceData& experience ) { - if(add_to_cache) - { - sCache[agent_id]=experience; + sCache[agent_id]=experience; - sPendingQueue.erase(agent_id); + sPendingQueue.erase(agent_id); + + //signal + signal_map_t::iterator sig_it = sSignalMap.find(agent_id); + if (sig_it != sSignalMap.end()) + { + callback_signal_t* signal = sig_it->second; + (*signal)(agent_id, experience); + sSignalMap.erase(agent_id); - //signal + delete signal; } } - void initClass( bool running ) + void initClass( ) { - sRunning = false; } const cache_t& getCached() @@ -77,6 +93,91 @@ namespace LLExperienceCache return sCache; } + void setMaximumLookups( int maximumLookups) + { + sMaximumLookups = maximumLookups; + } + + + bool expirationFromCacheControl(LLSD headers, F64 *expires) + { + // Allow the header to override the default + LLSD cache_control_header = headers["cache-control"]; + if (cache_control_header.isDefined()) + { + S32 max_age = 0; + std::string cache_control = cache_control_header.asString(); + if (max_age_from_cache_control(cache_control, &max_age)) + { + LL_DEBUGS("ExperienceCache") + << "got expiration from headers, max_age " << max_age + << LL_ENDL; + F64 now = LLFrameTimer::getTotalSeconds(); + *expires = now + (F64)max_age; + return true; + } + } + return false; + } + + + static const std::string MAX_AGE("max-age"); + static const boost::char_separator EQUALS_SEPARATOR("="); + static const boost::char_separator COMMA_SEPARATOR(","); + + bool max_age_from_cache_control(const std::string& cache_control, S32 *max_age) + { + // Split the string on "," to get a list of directives + typedef boost::tokenizer > tokenizer; + tokenizer directives(cache_control, COMMA_SEPARATOR); + + tokenizer::iterator token_it = directives.begin(); + for ( ; token_it != directives.end(); ++token_it) + { + // Tokens may have leading or trailing whitespace + std::string token = *token_it; + LLStringUtil::trim(token); + + if (token.compare(0, MAX_AGE.size(), MAX_AGE) == 0) + { + // ...this token starts with max-age, so let's chop it up by "=" + tokenizer subtokens(token, EQUALS_SEPARATOR); + tokenizer::iterator subtoken_it = subtokens.begin(); + + // Must have a token + if (subtoken_it == subtokens.end()) return false; + std::string subtoken = *subtoken_it; + + // Must exactly equal "max-age" + LLStringUtil::trim(subtoken); + if (subtoken != MAX_AGE) return false; + + // Must have another token + ++subtoken_it; + if (subtoken_it == subtokens.end()) return false; + subtoken = *subtoken_it; + + // Must be a valid integer + // *NOTE: atoi() returns 0 for invalid values, so we have to + // check the string first. + // *TODO: Do servers ever send "0000" for zero? We don't handle it + LLStringUtil::trim(subtoken); + if (subtoken == "0") + { + *max_age = 0; + return true; + } + S32 val = atoi( subtoken.c_str() ); + if (val > 0 && val < S32_MAX) + { + *max_age = val; + return true; + } + return false; + } + } + return false; + } void importFile(std::istream& istr) @@ -146,7 +247,7 @@ namespace LLExperienceCache LL_DEBUGS("ExperienceCache") << __FUNCTION__ << "Received result for " << agent_id << "display '" << experience.mDisplayName << "'" << LL_ENDL ; - processExperience(agent_id, experience, true); + processExperience(agent_id, experience); } } @@ -154,13 +255,74 @@ namespace LLExperienceCache S32 num_unresolved = unresolved_agents.size(); if(num_unresolved > 0) { - LL_DEBUGS("ExperienceCache") << __FUNCTION__ << "Ignoreing " << num_unresolved + LL_DEBUGS("ExperienceCache") << __FUNCTION__ << "Ignoring " << num_unresolved << " bad ids" << LL_ENDL ; } LL_DEBUGS("ExperienceCache") << __FUNCTION__ << sCache.size() << " cached experiences" << LL_ENDL; } + void error(U32 status, const std::string& reason) + { + // 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); + + LLExperienceData experience; + experience.mDisplayName = LLExperienceCache::DUMMY_NAME; + experience.mDescription = LLExperienceCache::DUMMY_NAME; + experience.mExpires = retry_timestamp; + + // Add dummy records for all agent IDs in this request + std::vector::const_iterator it = mAgentIds.begin(); + for ( ; it != mAgentIds.end(); ++it) + { + LLExperienceCache::processExperience((*it), experience); + } + } + + // 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) + { + F64 now = LLFrameTimer::getTotalSeconds(); + + // Retry-After takes priority + LLSD retry_after = mHeaders["retry-after"]; + if (retry_after.isDefined()) + { + // We only support the delta-seconds type + S32 delta_seconds = retry_after.asInteger(); + if (delta_seconds > 0) + { + // ...valid delta-seconds + return now + F64(delta_seconds); + } + } + + // If no Retry-After, look for Cache-Control max-age + F64 expires = 0.0; + if (LLExperienceCache::expirationFromCacheControl(mHeaders, &expires)) + { + return expires; + } + + // No information in header, make a guess + 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; + } + } + private: std::vector mAgentIds; LLSD mHeaders; @@ -186,13 +348,15 @@ namespace LLExperienceCache std::string arg="?ids="; - for(ask_queue_t::const_iterator it = sAskQueue.begin(); it != sAskQueue.end() ; ++it) + int request_count = 0; + for(ask_queue_t::const_iterator it = sAskQueue.begin() ; it != sAskQueue.end() && request_count < sMaximumLookups; ++it) { const LLUUID& agent_id = *it; url += arg; url += agent_id.asString(); agent_ids.push_back(agent_id); + request_count++; sPendingQueue[agent_id] = now; @@ -244,7 +408,20 @@ namespace LLExperienceCache void idle() { - sRunning = true; + + const F32 SECS_BETWEEN_REQUESTS = 0.1f; + if (!sRequestTimer.checkExpirationAndReset(SECS_BETWEEN_REQUESTS)) + { + return; + } + + // Must be large relative to above + const F32 ERASE_EXPIRED_TIMEOUT = 60.f; // seconds + if (sEraseExpiredTimer.checkExpirationAndReset(ERASE_EXPIRED_TIMEOUT)) + { + eraseExpired(); + } + if(!sAskQueue.empty()) { @@ -257,6 +434,25 @@ namespace LLExperienceCache sCache.erase(agent_id); } + void eraseExpired() + { + S32 expired_count = 0; + F64 now = LLFrameTimer::getTotalSeconds(); + cache_t::iterator it = sCache.begin(); + while (it != sCache.end()) + { + cache_t::iterator cur = it; + ++it; + const LLExperienceData& experience = cur->second; + if (experience.mExpires < now) + { + sCache.erase(cur); + expired_count++; + } + } + } + + void fetch( const LLUUID& agent_id ) { LL_DEBUGS("ExperienceCache") << __FUNCTION__ << "queue request for agent" << agent_id << LL_ENDL ; @@ -270,16 +466,12 @@ namespace LLExperienceCache bool get( const LLUUID& agent_id, LLExperienceData* experience_data ) { - if(sRunning) + cache_t::const_iterator it = sCache.find(agent_id); + if (it != sCache.end()) { - - cache_t::const_iterator it = sCache.find(agent_id); - if (it != sCache.end()) - { - llassert(experience_data); - *experience_data = it->second; - return true; - } + llassert(experience_data); + *experience_data = it->second; + return true; } if(!isRequestPending(agent_id)) @@ -291,12 +483,54 @@ namespace LLExperienceCache } + + void get( const LLUUID& agent_id, callback_slot_t slot ) + { + cache_t::const_iterator it = sCache.find(agent_id); + if (it != sCache.end()) + { + // ...name already exists in cache, fire callback now + callback_signal_t signal; + signal.connect(slot); + signal(agent_id, it->second); + return; + } + + // schedule a request + if (!isRequestPending(agent_id)) + { + sAskQueue.insert(agent_id); + } + + // always store additional callback, even if request is pending + signal_map_t::iterator sig_it = sSignalMap.find(agent_id); + if (sig_it == sSignalMap.end()) + { + // ...new callback for this id + callback_signal_t* signal = new callback_signal_t(); + signal->connect(slot); + sSignalMap[agent_id] = signal; + } + else + { + // ...existing callback, bind additional slot + callback_signal_t* signal = sig_it->second; + signal->connect(slot); + } + } + } +static const std::string EXPERIENCE_NAME("username"); +static const std::string EXPERIENCE_DESCRIPTION("display_name"); +static const std::string EXPERIENCE_EXPIRATION("display_name_expires"); + bool LLExperienceData::fromLLSD( const LLSD& sd ) { - mDisplayName = sd["display_name"].asString(); - mDescription = sd["username"].asString(); + mDisplayName = sd[EXPERIENCE_NAME].asString(); + mDescription = sd[EXPERIENCE_DESCRIPTION].asString(); + LLDate expiration = sd[EXPERIENCE_EXPIRATION]; + mExpires = expiration.secondsSinceEpoch(); if(mDisplayName.empty() || mDescription.empty()) return false; @@ -307,7 +541,9 @@ bool LLExperienceData::fromLLSD( const LLSD& sd ) LLSD LLExperienceData::asLLSD() const { LLSD sd; - sd["display_name"] = mDisplayName; - sd["username"] = mDescription.substr(0, llmin(mDescription.size(),mDescription.find(" %"))); + sd[EXPERIENCE_NAME] = mDisplayName; + sd[EXPERIENCE_DESCRIPTION] = mDescription.substr(0, llmin(mDescription.size(),mDescription.find(" %"))); + sd[EXPERIENCE_EXPIRATION] = LLDate(mExpires); + return sd; } -- cgit v1.2.3 From 179e944f45476e03eb7b828e427f9d299529ad12 Mon Sep 17 00:00:00 2001 From: dolphin Date: Tue, 18 Dec 2012 16:06:00 -0800 Subject: Updated client to use new caps brought over server changes to llExperienceCache --- indra/llmessage/llexperiencecache.cpp | 353 ++++++++++++++++++++-------------- 1 file changed, 208 insertions(+), 145 deletions(-) (limited to 'indra/llmessage/llexperiencecache.cpp') diff --git a/indra/llmessage/llexperiencecache.cpp b/indra/llmessage/llexperiencecache.cpp index 562c4c40df..18b950b61e 100644 --- a/indra/llmessage/llexperiencecache.cpp +++ b/indra/llmessage/llexperiencecache.cpp @@ -23,25 +23,26 @@ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ +#include "llexperiencecache.h" -#include "linden_common.h" #include "llavatarname.h" #include "llframetimer.h" #include "llhttpclient.h" #include "llsdserialize.h" #include #include -#include "boost\tokenizer.hpp" +#include "boost/tokenizer.hpp" + -#include "llexperiencecache.h" namespace LLExperienceCache { + const std::string& MAP_KEY = PUBLIC_KEY; std::string sLookupURL; - typedef std::set ask_queue_t; + typedef std::map ask_queue_t; ask_queue_t sAskQueue; typedef std::map pending_queue_t; @@ -65,20 +66,40 @@ namespace LLExperienceCache bool max_age_from_cache_control(const std::string& cache_control, S32 *max_age); void eraseExpired(); - void processExperience( const LLUUID& agent_id, const LLExperienceData& experience ) + void processExperience( const LLUUID& public_key, const LLSD& experience ) { - sCache[agent_id]=experience; + sCache[public_key]=experience; + LLSD & row = sCache[public_key]; + + if(row.has("expires")) + { + row["expires"] = row["expires"].asReal() + LLFrameTimer::getTotalSeconds(); + } + + if(row.has(PUBLIC_KEY)) + { + sPendingQueue.erase(row[PUBLIC_KEY].asUUID()); + } + + if(row.has(PRIVATE_KEY)) + { + sPendingQueue.erase(row[PRIVATE_KEY].asUUID()); + } + + if(row.has(CREATOR_KEY)) + { + sPendingQueue.erase(row[CREATOR_KEY].asUUID()); + } - sPendingQueue.erase(agent_id); //signal - signal_map_t::iterator sig_it = sSignalMap.find(agent_id); + signal_map_t::iterator sig_it = sSignalMap.find(public_key); if (sig_it != sSignalMap.end()) { callback_signal_t* signal = sig_it->second; - (*signal)(agent_id, experience); + (*signal)(experience); - sSignalMap.erase(agent_id); + sSignalMap.erase(public_key); delete signal; } @@ -109,7 +130,7 @@ namespace LLExperienceCache std::string cache_control = cache_control_header.asString(); if (max_age_from_cache_control(cache_control, &max_age)) { - LL_DEBUGS("ExperienceCache") + LL_WARNS("ExperienceCache") << "got expiration from headers, max_age " << max_age << LL_ENDL; F64 now = LLFrameTimer::getTotalSeconds(); @@ -186,16 +207,14 @@ namespace LLExperienceCache S32 parse_count = LLSDSerialize::fromXMLDocument(data, istr); if(parse_count < 1) return; - LLSD agents = data["agents"]; + LLSD experiences = data["experiences"]; - LLUUID agent_id; - LLExperienceData experience; - LLSD::map_const_iterator it = agents.beginMap(); - for(; it != agents.endMap() ; ++it) + LLUUID public_key; + LLSD::map_const_iterator it = experiences.beginMap(); + for(; it != experiences.endMap() ; ++it) { - agent_id.set(it->first); - experience.fromLLSD( it->second); - sCache[agent_id]=experience; + public_key.set(it->first); + sCache[public_key]=it->second; } LL_INFOS("ExperienceCache") << "loaded " << sCache.size() << LL_ENDL; @@ -203,16 +222,20 @@ namespace LLExperienceCache void exportFile(std::ostream& ostr) { - LLSD agents; + LLSD experiences; cache_t::const_iterator it =sCache.begin(); for( ; it != sCache.end() ; ++it) { - agents[it->first.asString()] = it->second.asLLSD(); + if(!it->second.has(PUBLIC_KEY) || it->second[PUBLIC_KEY].asUUID().isNull() || + it->second.has("error")) + continue; + + experiences[it->first.asString()] = it->second; } LLSD data; - data["agents"] = agents; + data["experiences"] = experiences; LLSDSerialize::toPrettyXML(data, ostr); } @@ -220,8 +243,8 @@ namespace LLExperienceCache class LLExperienceResponder : public LLHTTPClient::Responder { public: - LLExperienceResponder(const std::vector& agent_ids) - :mAgentIds(agent_ids) + LLExperienceResponder(const ask_queue_t& keys) + :mKeys(keys) { } @@ -233,60 +256,65 @@ namespace LLExperienceCache virtual void result(const LLSD& content) { - LLSD agents = content["agents"]; - LLSD::array_const_iterator it = agents.beginArray(); - for( /**/ ; it != agents.endArray(); ++it) + LLSD experiences = content["experience_keys"]; + LLSD::array_const_iterator it = experiences.beginArray(); + for( /**/ ; it != experiences.endArray(); ++it) { const LLSD& row = *it; - LLUUID agent_id = row["id"].asUUID(); + LLUUID public_key = row[PUBLIC_KEY].asUUID(); - LLExperienceData experience; - if(experience.fromLLSD(row)) - { - LL_DEBUGS("ExperienceCache") << __FUNCTION__ << "Received result for " << agent_id - << "display '" << experience.mDisplayName << "'" << LL_ENDL ; + LL_INFOS("ExperienceCache") << "Received result for " << public_key + << " display '" << row[LLExperienceCache::NAME].asString() << "'" << LL_ENDL ; - processExperience(agent_id, experience); - } + processExperience(public_key, row); } - LLSD unresolved_agents = content["bad_ids"]; - S32 num_unresolved = unresolved_agents.size(); - if(num_unresolved > 0) + LLSD error_ids = content["error_ids"]; + LLSD::map_const_iterator errIt = error_ids.beginMap(); + for( /**/ ; errIt != error_ids.endMap() ; ++errIt ) { - LL_DEBUGS("ExperienceCache") << __FUNCTION__ << "Ignoring " << num_unresolved - << " bad ids" << LL_ENDL ; + LLUUID id = LLUUID(errIt->first); + for( it = errIt->second.beginArray(); it != errIt->second.endArray() ; ++it) + { + LL_INFOS("ExperienceCache") << "Clearing error result for " << id + << " of type '" << it->asString() << "'" << LL_ENDL ; + + erase(id, it->asString()); + } } - LL_DEBUGS("ExperienceCache") << __FUNCTION__ << sCache.size() << " cached experiences" << LL_ENDL; + LL_INFOS("ExperienceCache") << sCache.size() << " cached experiences" << LL_ENDL; } - void error(U32 status, const std::string& reason) + virtual void error(U32 status, const std::string& reason) { - // 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); - - LLExperienceData experience; - experience.mDisplayName = LLExperienceCache::DUMMY_NAME; - experience.mDescription = LLExperienceCache::DUMMY_NAME; - experience.mExpires = retry_timestamp; - - // Add dummy records for all agent IDs in this request - std::vector::const_iterator it = mAgentIds.begin(); - for ( ; it != mAgentIds.end(); ++it) + LL_WARNS("ExperienceCache") << "Request failed "<second] = it->first; + exp["key_type"] = it->second; + exp["uuid"] = it->first; + exp["error"] = (LLSD::Integer)status; + LLExperienceCache::processExperience(it->first, exp); + } + } // 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) { - F64 now = LLFrameTimer::getTotalSeconds(); // Retry-After takes priority LLSD retry_after = mHeaders["retry-after"]; @@ -297,7 +325,7 @@ namespace LLExperienceCache if (delta_seconds > 0) { // ...valid delta-seconds - return now + F64(delta_seconds); + return F64(delta_seconds); } } @@ -313,78 +341,87 @@ namespace LLExperienceCache { // ...service unavailable, retry soon const F64 SERVICE_UNAVAILABLE_DELAY = 600.0; // 10 min - return now + SERVICE_UNAVAILABLE_DELAY; + return SERVICE_UNAVAILABLE_DELAY; + } + else if (status == 499) + { + // ...we were probably too busy, retry quickly + const F64 BUSY_DELAY = 10.0; // 10 seconds + return BUSY_DELAY; + } else { // ...other unexpected error const F64 DEFAULT_DELAY = 3600.0; // 1 hour - return now + DEFAULT_DELAY; + return DEFAULT_DELAY; } } private: - std::vector mAgentIds; + ask_queue_t mKeys; LLSD mHeaders; }; void requestExperiences() { - if(sAskQueue.empty()) + if(sAskQueue.empty() || sLookupURL.empty()) return; F64 now = LLFrameTimer::getTotalSeconds(); - const U32 NAME_URL_MAX = 4096; - const U32 NAME_URL_SEND_THRESHOLD = 3000; + const U32 EXP_URL_SEND_THRESHOLD = 3000; - std::string url; - url.reserve(NAME_URL_MAX); - std::vector agent_ids; - agent_ids.reserve(128); + std::ostringstream ostr; - url += sLookupURL; + ask_queue_t keys; - std::string arg="?ids="; + ostr << sLookupURL; + + char arg='?'; int request_count = 0; for(ask_queue_t::const_iterator it = sAskQueue.begin() ; it != sAskQueue.end() && request_count < sMaximumLookups; ++it) { - const LLUUID& agent_id = *it; + const LLUUID& key = it->first; + const std::string& key_type = it->second; + + ostr << arg << key_type << '=' << key.asString() ; - url += arg; - url += agent_id.asString(); - agent_ids.push_back(agent_id); + keys[key]=key_type; request_count++; - sPendingQueue[agent_id] = now; + sPendingQueue[key] = now; - arg[0]='&'; + arg='&'; - if(url.size() > NAME_URL_SEND_THRESHOLD) + if(ostr.tellp() > EXP_URL_SEND_THRESHOLD) { - LLHTTPClient::get(url, new LLExperienceResponder(agent_ids)); - url = sLookupURL; - arg[0]='?'; - agent_ids.clear(); + LL_INFOS("ExperienceCache") << " query: " << ostr.str() << LL_ENDL; + LLHTTPClient::get(ostr.str(), new LLExperienceResponder(keys)); + ostr.clear(); + ostr.str(sLookupURL); + arg='?'; + keys.clear(); } } - if(url.size() > sLookupURL.size()) + if(ostr.tellp() > sLookupURL.size()) { - LLHTTPClient::get(url, new LLExperienceResponder(agent_ids)); + LL_INFOS("ExperienceCache") << " query: " << ostr.str() << LL_ENDL; + LLHTTPClient::get(ostr.str(), new LLExperienceResponder(keys)); } sAskQueue.clear(); } - bool isRequestPending(const LLUUID& agent_id) + bool isRequestPending(const LLUUID& public_key) { bool isPending = false; const F64 PENDING_TIMEOUT_SECS = 5.0 * 60.0; - pending_queue_t::const_iterator it = sPendingQueue.find(agent_id); + pending_queue_t::const_iterator it = sPendingQueue.find(public_key); if(it != sPendingQueue.end()) { @@ -399,6 +436,10 @@ namespace LLExperienceCache void setLookupURL( const std::string& lookup_url ) { sLookupURL = lookup_url; + if(!sLookupURL.empty()) + { + sLookupURL += "id/"; + } } bool hasLookupURL() @@ -429,87 +470,136 @@ namespace LLExperienceCache } } - void erase( const LLUUID& agent_id ) + struct FindByKey + { + FindByKey(const LLUUID& key, const std::string& key_type):mKey(key), mKeyType(key_type){} + const LLUUID& mKey; + const std::string& mKeyType; + + bool operator()(cache_t::value_type& experience) + { + return experience.second.has(mKeyType) && experience.second[mKeyType].asUUID() == mKey; + } + }; + + + cache_t::iterator Find(const LLUUID& key, const std::string& key_type) + { + LL_INFOS("ExperienceCache") << " searching for " << key << " of type " << key_type << LL_ENDL; + if(key_type == MAP_KEY) + { + return sCache.find(key); + } + + return std::find_if(sCache.begin(), sCache.end(), FindByKey(key, key_type)); + } + + + void erase( const LLUUID& key, const std::string& key_type ) { - sCache.erase(agent_id); + cache_t::iterator it = Find(key, key_type); + + if(it != sCache.end()) + { + sCache.erase(it); + } } void eraseExpired() { - S32 expired_count = 0; F64 now = LLFrameTimer::getTotalSeconds(); cache_t::iterator it = sCache.begin(); while (it != sCache.end()) { cache_t::iterator cur = it; + LLSD& exp = cur->second; ++it; - const LLExperienceData& experience = cur->second; - if (experience.mExpires < now) + if(exp.has("expires") && exp["expires"].asReal() < now) { - sCache.erase(cur); - expired_count++; + if(exp.has("key_type") && exp.has("uuid")) + { + fetch(exp["uuid"].asUUID(), exp["key_type"].asString(), true); + sCache.erase(cur); + } + else if(exp.has(MAP_KEY)) + { + LLUUID id = exp[MAP_KEY]; + if(!id.isNull()) + { + fetch(id, MAP_KEY, true); + } + } } } } - - void fetch( const LLUUID& agent_id ) + + bool fetch( const LLUUID& key, const std::string& key_type, bool refresh/* = true*/ ) { - LL_DEBUGS("ExperienceCache") << __FUNCTION__ << "queue request for agent" << agent_id << LL_ENDL ; - sAskQueue.insert(agent_id); + if(!key.isNull() && !isRequestPending(key) && (refresh || Find(key, key_type)==sCache.end())) + { + LL_INFOS("ExperienceCache") << " queue request for " << key_type << " " << key << LL_ENDL ; + sAskQueue[key]=key_type; + + return true; + } + return false; } - void insert( const LLUUID& agent_id, const LLExperienceData& experience_data ) + void insert(const LLSD& experience_data ) { - sCache[agent_id]=experience_data; + if(experience_data.has(MAP_KEY)) + { + sCache[experience_data[MAP_KEY].asUUID()]=experience_data; + } + else + { + LL_WARNS("ExperienceCache") << ": Ignoring cache insert of experience which is missing " << MAP_KEY << LL_ENDL; + } } - bool get( const LLUUID& agent_id, LLExperienceData* experience_data ) + bool get( const LLUUID& key, const std::string& key_type, LLSD& experience_data ) { - cache_t::const_iterator it = sCache.find(agent_id); + if(key.isNull()) return false; + cache_t::const_iterator it = Find(key, key_type); + if (it != sCache.end()) { - llassert(experience_data); - *experience_data = it->second; + experience_data = it->second; return true; } - if(!isRequestPending(agent_id)) - { - fetch(agent_id); - } + fetch(key, key_type); return false; } - - void get( const LLUUID& agent_id, callback_slot_t slot ) + void get( const LLUUID& key, const std::string& key_type, callback_slot_t slot ) { - cache_t::const_iterator it = sCache.find(agent_id); + if(key.isNull()) return; + + cache_t::const_iterator it = Find(key, key_type); if (it != sCache.end()) { // ...name already exists in cache, fire callback now callback_signal_t signal; signal.connect(slot); - signal(agent_id, it->second); + + signal(it->second); return; } - // schedule a request - if (!isRequestPending(agent_id)) - { - sAskQueue.insert(agent_id); - } + fetch(key, key_type); // always store additional callback, even if request is pending - signal_map_t::iterator sig_it = sSignalMap.find(agent_id); + signal_map_t::iterator sig_it = sSignalMap.find(key); if (sig_it == sSignalMap.end()) { // ...new callback for this id callback_signal_t* signal = new callback_signal_t(); signal->connect(slot); - sSignalMap[agent_id] = signal; + sSignalMap[key] = signal; } else { @@ -520,30 +610,3 @@ namespace LLExperienceCache } } - -static const std::string EXPERIENCE_NAME("username"); -static const std::string EXPERIENCE_DESCRIPTION("display_name"); -static const std::string EXPERIENCE_EXPIRATION("display_name_expires"); - -bool LLExperienceData::fromLLSD( const LLSD& sd ) -{ - mDisplayName = sd[EXPERIENCE_NAME].asString(); - mDescription = sd[EXPERIENCE_DESCRIPTION].asString(); - LLDate expiration = sd[EXPERIENCE_EXPIRATION]; - mExpires = expiration.secondsSinceEpoch(); - - if(mDisplayName.empty() || mDescription.empty()) return false; - - mDescription += " % Hey, this is a description!"; - return true; -} - -LLSD LLExperienceData::asLLSD() const -{ - LLSD sd; - sd[EXPERIENCE_NAME] = mDisplayName; - sd[EXPERIENCE_DESCRIPTION] = mDescription.substr(0, llmin(mDescription.size(),mDescription.find(" %"))); - sd[EXPERIENCE_EXPIRATION] = LLDate(mExpires); - - return sd; -} -- cgit v1.2.3 From 61874872a7b4b8909f835650ab6732e24c61ffa2 Mon Sep 17 00:00:00 2001 From: dolphin Date: Wed, 13 Feb 2013 14:20:35 -0800 Subject: Updated experience cache to latest web service api Added new CAP request for experiences the avatar can sign --- indra/llmessage/llexperiencecache.cpp | 156 ++++++++++++++++++++-------------- 1 file changed, 94 insertions(+), 62 deletions(-) (limited to 'indra/llmessage/llexperiencecache.cpp') diff --git a/indra/llmessage/llexperiencecache.cpp b/indra/llmessage/llexperiencecache.cpp index 18b950b61e..1a6e74d123 100644 --- a/indra/llmessage/llexperiencecache.cpp +++ b/indra/llmessage/llexperiencecache.cpp @@ -34,12 +34,15 @@ #include "boost/tokenizer.hpp" +namespace LLExperienceCache +{ + typedef std::map PrivateKeyMap; + PrivateKeyMap experinceKeyMap; + + void mapPrivateKeys(const LLSD& legacyKeys); -namespace LLExperienceCache -{ - const std::string& MAP_KEY = PUBLIC_KEY; std::string sLookupURL; typedef std::map ask_queue_t; @@ -76,19 +79,14 @@ namespace LLExperienceCache row["expires"] = row["expires"].asReal() + LLFrameTimer::getTotalSeconds(); } - if(row.has(PUBLIC_KEY)) - { - sPendingQueue.erase(row[PUBLIC_KEY].asUUID()); - } - - if(row.has(PRIVATE_KEY)) + if(row.has(EXPERIENCE_ID)) { - sPendingQueue.erase(row[PRIVATE_KEY].asUUID()); + sPendingQueue.erase(row[EXPERIENCE_ID].asUUID()); } - if(row.has(CREATOR_KEY)) + if(row.has(OWNER_ID)) { - sPendingQueue.erase(row[CREATOR_KEY].asUUID()); + sPendingQueue.erase(row[OWNER_ID].asUUID()); } @@ -119,6 +117,31 @@ namespace LLExperienceCache sMaximumLookups = maximumLookups; } + void bootstrap(const LLSD& legacyKeys, int initialExpiration) + { + mapPrivateKeys(legacyKeys); + LLSD::array_const_iterator it = legacyKeys.beginArray(); + for(/**/; it != legacyKeys.endArray(); ++it) + { + LLSD experience = *it; + if(experience.has(EXPERIENCE_ID)) + { + if(!experience.has("expires")) + { + experience["expires"] = initialExpiration; + } + processExperience(experience[EXPERIENCE_ID].asUUID(), experience); + } + else + { + LL_WARNS("ExperienceCache") + << "Skipping bootstrap entry which is missing " << EXPERIENCE_ID + << LL_ENDL; + } + } + } + + bool expirationFromCacheControl(LLSD headers, F64 *expires) { @@ -227,7 +250,7 @@ namespace LLExperienceCache cache_t::const_iterator it =sCache.begin(); for( ; it != sCache.end() ; ++it) { - if(!it->second.has(PUBLIC_KEY) || it->second[PUBLIC_KEY].asUUID().isNull() || + if(!it->second.has(EXPERIENCE_ID) || it->second[EXPERIENCE_ID].asUUID().isNull() || it->second.has("error")) continue; @@ -261,7 +284,7 @@ namespace LLExperienceCache for( /**/ ; it != experiences.endArray(); ++it) { const LLSD& row = *it; - LLUUID public_key = row[PUBLIC_KEY].asUUID(); + LLUUID public_key = row[EXPERIENCE_ID].asUUID(); LL_INFOS("ExperienceCache") << "Received result for " << public_key @@ -280,7 +303,7 @@ namespace LLExperienceCache LL_INFOS("ExperienceCache") << "Clearing error result for " << id << " of type '" << it->asString() << "'" << LL_ENDL ; - erase(id, it->asString()); + erase(id); } } @@ -301,8 +324,8 @@ namespace LLExperienceCache for ( ; it != mKeys.end(); ++it) { LLSD exp; - exp["expires"]=retry_timestamp; - exp[it->second] = it->first; + exp[EXPIRES]=retry_timestamp; + exp[EXPERIENCE_ID] = it->first; exp["key_type"] = it->second; exp["uuid"] = it->first; exp["error"] = (LLSD::Integer)status; @@ -470,34 +493,9 @@ namespace LLExperienceCache } } - struct FindByKey + void erase( const LLUUID& key ) { - FindByKey(const LLUUID& key, const std::string& key_type):mKey(key), mKeyType(key_type){} - const LLUUID& mKey; - const std::string& mKeyType; - - bool operator()(cache_t::value_type& experience) - { - return experience.second.has(mKeyType) && experience.second[mKeyType].asUUID() == mKey; - } - }; - - - cache_t::iterator Find(const LLUUID& key, const std::string& key_type) - { - LL_INFOS("ExperienceCache") << " searching for " << key << " of type " << key_type << LL_ENDL; - if(key_type == MAP_KEY) - { - return sCache.find(key); - } - - return std::find_if(sCache.begin(), sCache.end(), FindByKey(key, key_type)); - } - - - void erase( const LLUUID& key, const std::string& key_type ) - { - cache_t::iterator it = Find(key, key_type); + cache_t::iterator it = sCache.find(key); if(it != sCache.end()) { @@ -518,15 +516,15 @@ namespace LLExperienceCache { if(exp.has("key_type") && exp.has("uuid")) { - fetch(exp["uuid"].asUUID(), exp["key_type"].asString(), true); + fetch(exp[EXPERIENCE_ID].asUUID(), true); sCache.erase(cur); } - else if(exp.has(MAP_KEY)) + else if(exp.has(EXPERIENCE_ID)) { - LLUUID id = exp[MAP_KEY]; - if(!id.isNull()) + LLUUID id = exp[EXPERIENCE_ID].asUUID(); + if(id.notNull()) { - fetch(id, MAP_KEY, true); + fetch(id, true); } } } @@ -534,12 +532,12 @@ namespace LLExperienceCache } - bool fetch( const LLUUID& key, const std::string& key_type, bool refresh/* = true*/ ) + bool fetch( const LLUUID& key, bool refresh/* = true*/ ) { - if(!key.isNull() && !isRequestPending(key) && (refresh || Find(key, key_type)==sCache.end())) + if(!key.isNull() && !isRequestPending(key) && (refresh || sCache.find(key)==sCache.end())) { - LL_INFOS("ExperienceCache") << " queue request for " << key_type << " " << key << LL_ENDL ; - sAskQueue[key]=key_type; + LL_INFOS("ExperienceCache") << " queue request for " << EXPERIENCE_ID << " " << key << LL_ENDL ; + sAskQueue[key]=EXPERIENCE_ID; return true; } @@ -548,20 +546,20 @@ namespace LLExperienceCache void insert(const LLSD& experience_data ) { - if(experience_data.has(MAP_KEY)) + if(experience_data.has(EXPERIENCE_ID)) { - sCache[experience_data[MAP_KEY].asUUID()]=experience_data; + sCache[experience_data[EXPERIENCE_ID].asUUID()]=experience_data; } else { - LL_WARNS("ExperienceCache") << ": Ignoring cache insert of experience which is missing " << MAP_KEY << LL_ENDL; + LL_WARNS("ExperienceCache") << ": Ignoring cache insert of experience which is missing " << EXPERIENCE_ID << LL_ENDL; } } - bool get( const LLUUID& key, const std::string& key_type, LLSD& experience_data ) + bool get( const LLUUID& key, LLSD& experience_data ) { if(key.isNull()) return false; - cache_t::const_iterator it = Find(key, key_type); + cache_t::const_iterator it = sCache.find(key); if (it != sCache.end()) { @@ -569,17 +567,17 @@ namespace LLExperienceCache return true; } - fetch(key, key_type); + fetch(key); return false; } - void get( const LLUUID& key, const std::string& key_type, callback_slot_t slot ) + void get( const LLUUID& key, callback_slot_t slot ) { if(key.isNull()) return; - cache_t::const_iterator it = Find(key, key_type); + cache_t::const_iterator it = sCache.find(key); if (it != sCache.end()) { // ...name already exists in cache, fire callback now @@ -590,7 +588,7 @@ namespace LLExperienceCache return; } - fetch(key, key_type); + fetch(key); // always store additional callback, even if request is pending signal_map_t::iterator sig_it = sSignalMap.find(key); @@ -610,3 +608,37 @@ namespace LLExperienceCache } } + + + +void LLExperienceCache::mapPrivateKeys( const LLSD& legacyKeys ) +{ + LLSD::array_const_iterator exp = legacyKeys.beginArray(); + for(/**/ ; exp != legacyKeys.endArray() ; ++exp) + { + if(exp->has(LLExperienceCache::EXPERIENCE_ID) && exp->has(LLExperienceCache::PRIVATE_KEY)) + { + experinceKeyMap[(*exp)[LLExperienceCache::PRIVATE_KEY].asUUID()]=(*exp)[LLExperienceCache::EXPERIENCE_ID].asUUID(); + } + } +} + + +LLUUID LLExperienceCache::getExperienceId(const LLUUID& private_key, bool null_if_not_found) +{ + if (private_key.isNull()) + return LLUUID::null; + + + PrivateKeyMap::const_iterator it=experinceKeyMap.find(private_key); + if(it == experinceKeyMap.end()) + { + if(null_if_not_found) + { + return LLUUID::null; + } + return private_key; + } + LL_WARNS("LLExperience") << "converted private key " << private_key << " to experience_id " << it->second << LL_ENDL; + return it->second; +} -- cgit v1.2.3 From d5308c19f7c622538d61e3ebb174338ce95a7b72 Mon Sep 17 00:00:00 2001 From: dolphin Date: Wed, 13 Mar 2013 10:24:30 -0700 Subject: Fixed up expiration code for the experience cache --- indra/llmessage/llexperiencecache.cpp | 52 +++++++++++++++++++---------------- 1 file changed, 29 insertions(+), 23 deletions(-) (limited to 'indra/llmessage/llexperiencecache.cpp') diff --git a/indra/llmessage/llexperiencecache.cpp b/indra/llmessage/llexperiencecache.cpp index 1a6e74d123..219e68b51c 100644 --- a/indra/llmessage/llexperiencecache.cpp +++ b/indra/llmessage/llexperiencecache.cpp @@ -74,9 +74,9 @@ namespace LLExperienceCache sCache[public_key]=experience; LLSD & row = sCache[public_key]; - if(row.has("expires")) + if(row.has(EXPIRES)) { - row["expires"] = row["expires"].asReal() + LLFrameTimer::getTotalSeconds(); + row[EXPIRES] = row[EXPIRES].asReal() + LLFrameTimer::getTotalSeconds(); } if(row.has(EXPERIENCE_ID)) @@ -126,9 +126,9 @@ namespace LLExperienceCache LLSD experience = *it; if(experience.has(EXPERIENCE_ID)) { - if(!experience.has("expires")) + if(!experience.has(EXPIRES)) { - experience["expires"] = initialExpiration; + experience[EXPIRES] = initialExpiration; } processExperience(experience[EXPERIENCE_ID].asUUID(), experience); } @@ -154,7 +154,7 @@ namespace LLExperienceCache if (max_age_from_cache_control(cache_control, &max_age)) { LL_WARNS("ExperienceCache") - << "got expiration from headers, max_age " << max_age + << "got EXPIRES from headers, max_age " << max_age << LL_ENDL; F64 now = LLFrameTimer::getTotalSeconds(); *expires = now + (F64)max_age; @@ -251,7 +251,7 @@ namespace LLExperienceCache for( ; it != sCache.end() ; ++it) { if(!it->second.has(EXPERIENCE_ID) || it->second[EXPERIENCE_ID].asUUID().isNull() || - it->second.has("error")) + it->second.has("DoesNotExist") || (it->second.has(PROPERTIES) && it->second[PROPERTIES].asInteger() & PROPERTY_INVALID)) continue; experiences[it->first.asString()] = it->second; @@ -294,17 +294,18 @@ namespace LLExperienceCache } LLSD error_ids = content["error_ids"]; - LLSD::map_const_iterator errIt = error_ids.beginMap(); - for( /**/ ; errIt != error_ids.endMap() ; ++errIt ) + LLSD::array_const_iterator errIt = error_ids.beginArray(); + for( /**/ ; errIt != error_ids.endArray() ; ++errIt ) { - LLUUID id = LLUUID(errIt->first); - for( it = errIt->second.beginArray(); it != errIt->second.endArray() ; ++it) - { - LL_INFOS("ExperienceCache") << "Clearing error result for " << id - << " of type '" << it->asString() << "'" << LL_ENDL ; + LLUUID id = errIt->asUUID(); + LLSD exp; + exp[EXPIRES]=DEFAULT_EXPIRATION; + exp[EXPERIENCE_ID] = id; + exp[PROPERTIES]=PROPERTY_INVALID; + exp["DoesNotExist"]=true; - erase(id); - } + processExperience(id, exp); + LL_INFOS("ExperienceCache") << "Error result for " << id << LL_ENDL ; } LL_INFOS("ExperienceCache") << sCache.size() << " cached experiences" << LL_ENDL; @@ -329,6 +330,7 @@ namespace LLExperienceCache exp["key_type"] = it->second; exp["uuid"] = it->first; exp["error"] = (LLSD::Integer)status; + exp[PROPERTIES]=PROPERTY_INVALID; LLExperienceCache::processExperience(it->first, exp); } @@ -512,20 +514,24 @@ namespace LLExperienceCache cache_t::iterator cur = it; LLSD& exp = cur->second; ++it; - if(exp.has("expires") && exp["expires"].asReal() < now) + if(exp.has(EXPIRES) && exp[EXPIRES].asReal() < now) { - if(exp.has("key_type") && exp.has("uuid")) - { - fetch(exp[EXPERIENCE_ID].asUUID(), true); - sCache.erase(cur); - } - else if(exp.has(EXPERIENCE_ID)) + if(exp.has(EXPERIENCE_ID)) { LLUUID id = exp[EXPERIENCE_ID].asUUID(); - if(id.notNull()) + S32 properties = PROPERTY_INVALID; + if(exp.has(PROPERTIES)) + { + properties = exp[PROPERTIES].asInteger(); + } + if(id.notNull() && ((properties & PROPERTY_INVALID) == 0)) { fetch(id, true); } + else + { + sCache.erase(cur); + } } } } -- cgit v1.2.3 From 257110c11e5546f0a5a07b087694cfc9059367b4 Mon Sep 17 00:00:00 2001 From: dolphin Date: Wed, 21 Aug 2013 15:43:09 -0700 Subject: Added new fields to the experience cache. Experience profile moved to it's own floater, will probalby be moving again. XP profile displays most data, though the presentation is not final Fixed a bug with the XP selection combobox in the script editor --- indra/llmessage/llexperiencecache.cpp | 61 +++++++++++++++++++++++------------ 1 file changed, 41 insertions(+), 20 deletions(-) (limited to 'indra/llmessage/llexperiencecache.cpp') diff --git a/indra/llmessage/llexperiencecache.cpp b/indra/llmessage/llexperiencecache.cpp index 219e68b51c..2e260ecdef 100644 --- a/indra/llmessage/llexperiencecache.cpp +++ b/indra/llmessage/llexperiencecache.cpp @@ -37,11 +37,10 @@ namespace LLExperienceCache { - typedef std::map PrivateKeyMap; - PrivateKeyMap experinceKeyMap; - - void mapPrivateKeys(const LLSD& legacyKeys); + typedef std::map KeyMap; + KeyMap privateToPublicKeyMap; + void mapKeys(const LLSD& legacyKeys); std::string sLookupURL; @@ -66,6 +65,7 @@ namespace LLExperienceCache signal_map_t sSignalMap; + bool max_age_from_cache_control(const std::string& cache_control, S32 *max_age); void eraseExpired(); @@ -89,6 +89,17 @@ namespace LLExperienceCache sPendingQueue.erase(row[OWNER_ID].asUUID()); } + if(!row.has(OWNER_ID)) + { + if(row.has(AGENT_ID) && row[AGENT_ID].asUUID().notNull()) + { + row[OWNER_ID]=row[AGENT_ID]; + } + else + { + row[OWNER_ID]=row[GROUP_ID]; + } + } //signal signal_map_t::iterator sig_it = sSignalMap.find(public_key); @@ -119,7 +130,7 @@ namespace LLExperienceCache void bootstrap(const LLSD& legacyKeys, int initialExpiration) { - mapPrivateKeys(legacyKeys); + mapKeys(legacyKeys); LLSD::array_const_iterator it = legacyKeys.beginArray(); for(/**/; it != legacyKeys.endArray(); ++it) { @@ -302,7 +313,8 @@ namespace LLExperienceCache exp[EXPIRES]=DEFAULT_EXPIRATION; exp[EXPERIENCE_ID] = id; exp[PROPERTIES]=PROPERTY_INVALID; - exp["DoesNotExist"]=true; + exp[MISSING]=true; + exp[QUOTA] = DEFAULT_QUOTA; processExperience(id, exp); LL_INFOS("ExperienceCache") << "Error result for " << id << LL_ENDL ; @@ -324,14 +336,22 @@ namespace LLExperienceCache ask_queue_t::const_iterator it = mKeys.begin(); for ( ; it != mKeys.end(); ++it) { + LLSD exp; + //leave the properties alone if we already have a cache entry for this xp + if(!get(it->first, exp)) + { + exp[PROPERTIES]=PROPERTY_INVALID; + } exp[EXPIRES]=retry_timestamp; exp[EXPERIENCE_ID] = it->first; exp["key_type"] = it->second; exp["uuid"] = it->first; exp["error"] = (LLSD::Integer)status; - exp[PROPERTIES]=PROPERTY_INVALID; + exp[QUOTA] = DEFAULT_QUOTA; + LLExperienceCache::processExperience(it->first, exp); + LL_INFOS("ExperienceCache") << "Error result for " << it->first << LL_ENDL ; } } @@ -514,22 +534,25 @@ namespace LLExperienceCache cache_t::iterator cur = it; LLSD& exp = cur->second; ++it; + if(exp.has(EXPIRES) && exp[EXPIRES].asReal() < now) { - if(exp.has(EXPERIENCE_ID)) + if(!exp.has(EXPERIENCE_ID)) { - LLUUID id = exp[EXPERIENCE_ID].asUUID(); - S32 properties = PROPERTY_INVALID; - if(exp.has(PROPERTIES)) - { - properties = exp[PROPERTIES].asInteger(); + LL_INFOS("ExperienceCache") << "Removing experience with no id " << LL_ENDL ; + sCache.erase(cur); } - if(id.notNull() && ((properties & PROPERTY_INVALID) == 0)) + else + { + LLUUID id = exp[EXPERIENCE_ID].asUUID(); + LLUUID private_key = exp.has(LLExperienceCache::PRIVATE_KEY) ? exp[LLExperienceCache::PRIVATE_KEY].asUUID():LLUUID::null; + if(private_key.notNull() || !exp.has("DoesNotExist")) { fetch(id, true); } else { + LL_INFOS("ExperienceCache") << "Removing invalid experience " << id << LL_ENDL ; sCache.erase(cur); } } @@ -616,15 +639,14 @@ namespace LLExperienceCache } - -void LLExperienceCache::mapPrivateKeys( const LLSD& legacyKeys ) +void LLExperienceCache::mapKeys( const LLSD& legacyKeys ) { LLSD::array_const_iterator exp = legacyKeys.beginArray(); for(/**/ ; exp != legacyKeys.endArray() ; ++exp) { if(exp->has(LLExperienceCache::EXPERIENCE_ID) && exp->has(LLExperienceCache::PRIVATE_KEY)) { - experinceKeyMap[(*exp)[LLExperienceCache::PRIVATE_KEY].asUUID()]=(*exp)[LLExperienceCache::EXPERIENCE_ID].asUUID(); + privateToPublicKeyMap[(*exp)[LLExperienceCache::PRIVATE_KEY].asUUID()]=(*exp)[LLExperienceCache::EXPERIENCE_ID].asUUID(); } } } @@ -635,9 +657,8 @@ LLUUID LLExperienceCache::getExperienceId(const LLUUID& private_key, bool null_i if (private_key.isNull()) return LLUUID::null; - - PrivateKeyMap::const_iterator it=experinceKeyMap.find(private_key); - if(it == experinceKeyMap.end()) + KeyMap::const_iterator it=privateToPublicKeyMap.find(private_key); + if(it == privateToPublicKeyMap.end()) { if(null_if_not_found) { -- cgit v1.2.3 From 51c01f5294b68b66706685346ecea16246b85cce Mon Sep 17 00:00:00 2001 From: dolphin Date: Mon, 9 Sep 2013 11:19:41 -0700 Subject: More explicitnexx for the mac build Also update the experience cache when the update returns. --- indra/llmessage/llexperiencecache.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra/llmessage/llexperiencecache.cpp') diff --git a/indra/llmessage/llexperiencecache.cpp b/indra/llmessage/llexperiencecache.cpp index 2e260ecdef..b131156905 100644 --- a/indra/llmessage/llexperiencecache.cpp +++ b/indra/llmessage/llexperiencecache.cpp @@ -577,7 +577,7 @@ namespace LLExperienceCache { if(experience_data.has(EXPERIENCE_ID)) { - sCache[experience_data[EXPERIENCE_ID].asUUID()]=experience_data; + processExperience(experience_data[EXPERIENCE_ID].asUUID(), experience_data); } else { -- cgit v1.2.3 From f5b7343238626f52ea45ee74ed06294ae1f22a74 Mon Sep 17 00:00:00 2001 From: dolphin Date: Tue, 17 Sep 2013 19:58:20 -0700 Subject: Updated position of the edit button the experience profile and added the Grid Wide tag. --- indra/llmessage/llexperiencecache.cpp | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) (limited to 'indra/llmessage/llexperiencecache.cpp') diff --git a/indra/llmessage/llexperiencecache.cpp b/indra/llmessage/llexperiencecache.cpp index b131156905..921c1edc2e 100644 --- a/indra/llmessage/llexperiencecache.cpp +++ b/indra/llmessage/llexperiencecache.cpp @@ -251,7 +251,7 @@ namespace LLExperienceCache sCache[public_key]=it->second; } - LL_INFOS("ExperienceCache") << "loaded " << sCache.size() << LL_ENDL; + LL_DEBUGS("ExperienceCache") << "importFile() loaded " << sCache.size() << LL_ENDL; } void exportFile(std::ostream& ostr) @@ -298,7 +298,7 @@ namespace LLExperienceCache LLUUID public_key = row[EXPERIENCE_ID].asUUID(); - LL_INFOS("ExperienceCache") << "Received result for " << public_key + LL_DEBUGS("ExperienceCache") << "Received result for " << public_key << " display '" << row[LLExperienceCache::NAME].asString() << "'" << LL_ENDL ; processExperience(public_key, row); @@ -317,10 +317,10 @@ namespace LLExperienceCache exp[QUOTA] = DEFAULT_QUOTA; processExperience(id, exp); - LL_INFOS("ExperienceCache") << "Error result for " << id << LL_ENDL ; + LL_WARNS("ExperienceCache") << "LLExperienceResponder::result() error result for " << id << LL_ENDL ; } - LL_INFOS("ExperienceCache") << sCache.size() << " cached experiences" << LL_ENDL; + LL_DEBUGS("ExperienceCache") << sCache.size() << " cached experiences" << LL_ENDL; } virtual void error(U32 status, const std::string& reason) @@ -351,7 +351,6 @@ namespace LLExperienceCache exp[QUOTA] = DEFAULT_QUOTA; LLExperienceCache::processExperience(it->first, exp); - LL_INFOS("ExperienceCache") << "Error result for " << it->first << LL_ENDL ; } } @@ -443,7 +442,7 @@ namespace LLExperienceCache if(ostr.tellp() > EXP_URL_SEND_THRESHOLD) { - LL_INFOS("ExperienceCache") << " query: " << ostr.str() << LL_ENDL; + LL_DEBUGS("ExperienceCache") << "requestExperiences() query: " << ostr.str() << LL_ENDL; LLHTTPClient::get(ostr.str(), new LLExperienceResponder(keys)); ostr.clear(); ostr.str(sLookupURL); @@ -454,7 +453,7 @@ namespace LLExperienceCache if(ostr.tellp() > sLookupURL.size()) { - LL_INFOS("ExperienceCache") << " query: " << ostr.str() << LL_ENDL; + LL_DEBUGS("ExperienceCache") << "requestExperiences() query 2: " << ostr.str() << LL_ENDL; LLHTTPClient::get(ostr.str(), new LLExperienceResponder(keys)); } @@ -539,7 +538,7 @@ namespace LLExperienceCache { if(!exp.has(EXPERIENCE_ID)) { - LL_INFOS("ExperienceCache") << "Removing experience with no id " << LL_ENDL ; + LL_WARNS("ExperienceCache") << "Removing experience with no id " << LL_ENDL ; sCache.erase(cur); } else @@ -552,7 +551,7 @@ namespace LLExperienceCache } else { - LL_INFOS("ExperienceCache") << "Removing invalid experience " << id << LL_ENDL ; + LL_WARNS("ExperienceCache") << "Removing invalid experience " << id << LL_ENDL ; sCache.erase(cur); } } @@ -565,7 +564,7 @@ namespace LLExperienceCache { if(!key.isNull() && !isRequestPending(key) && (refresh || sCache.find(key)==sCache.end())) { - LL_INFOS("ExperienceCache") << " queue request for " << EXPERIENCE_ID << " " << key << LL_ENDL ; + LL_DEBUGS("ExperienceCache") << " queue request for " << EXPERIENCE_ID << " " << key << LL_ENDL ; sAskQueue[key]=EXPERIENCE_ID; return true; -- cgit v1.2.3 From 7b9817cbcc5acab58d9d4355984b429850bd3ef8 Mon Sep 17 00:00:00 2001 From: dolphin Date: Mon, 10 Mar 2014 10:15:19 -0700 Subject: Fixed a bug that lost callbacks if > 10 experiences were looked up at a time. --- indra/llmessage/llexperiencecache.cpp | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) (limited to 'indra/llmessage/llexperiencecache.cpp') diff --git a/indra/llmessage/llexperiencecache.cpp b/indra/llmessage/llexperiencecache.cpp index 921c1edc2e..5cca918baf 100644 --- a/indra/llmessage/llexperiencecache.cpp +++ b/indra/llmessage/llexperiencecache.cpp @@ -415,40 +415,39 @@ namespace LLExperienceCache F64 now = LLFrameTimer::getTotalSeconds(); const U32 EXP_URL_SEND_THRESHOLD = 3000; - + const U32 PAGE_SIZE = EXP_URL_SEND_THRESHOLD/UUID_STR_LENGTH; std::ostringstream ostr; ask_queue_t keys; - ostr << sLookupURL; + ostr << sLookupURL << "?page_size=" << PAGE_SIZE; - char arg='?'; int request_count = 0; - for(ask_queue_t::const_iterator it = sAskQueue.begin() ; it != sAskQueue.end() && request_count < sMaximumLookups; ++it) + while(!sAskQueue.empty() && request_count < sMaximumLookups) { + ask_queue_t::const_iterator it = sAskQueue.begin(); const LLUUID& key = it->first; const std::string& key_type = it->second; - ostr << arg << key_type << '=' << key.asString() ; + ostr << '&' << key_type << '=' << key.asString() ; keys[key]=key_type; request_count++; sPendingQueue[key] = now; - - arg='&'; - + if(ostr.tellp() > EXP_URL_SEND_THRESHOLD) { LL_DEBUGS("ExperienceCache") << "requestExperiences() query: " << ostr.str() << LL_ENDL; LLHTTPClient::get(ostr.str(), new LLExperienceResponder(keys)); ostr.clear(); ostr.str(sLookupURL); - arg='?'; + ostr << "?page_size=" << PAGE_SIZE; keys.clear(); } + sAskQueue.erase(it); } if(ostr.tellp() > sLookupURL.size()) @@ -456,8 +455,6 @@ namespace LLExperienceCache LL_DEBUGS("ExperienceCache") << "requestExperiences() query 2: " << ostr.str() << LL_ENDL; LLHTTPClient::get(ostr.str(), new LLExperienceResponder(keys)); } - - sAskQueue.clear(); } bool isRequestPending(const LLUUID& public_key) -- cgit v1.2.3 From a0b8c3e029be9265152cb8919ebe9c2bc328b766 Mon Sep 17 00:00:00 2001 From: dolphin Date: Wed, 12 Mar 2014 11:49:17 -0700 Subject: Windows lets you erase with a const iterator but linux does not. --- indra/llmessage/llexperiencecache.cpp | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-) (limited to 'indra/llmessage/llexperiencecache.cpp') diff --git a/indra/llmessage/llexperiencecache.cpp b/indra/llmessage/llexperiencecache.cpp index 5cca918baf..648e2039a6 100644 --- a/indra/llmessage/llexperiencecache.cpp +++ b/indra/llmessage/llexperiencecache.cpp @@ -84,23 +84,6 @@ namespace LLExperienceCache sPendingQueue.erase(row[EXPERIENCE_ID].asUUID()); } - if(row.has(OWNER_ID)) - { - sPendingQueue.erase(row[OWNER_ID].asUUID()); - } - - if(!row.has(OWNER_ID)) - { - if(row.has(AGENT_ID) && row[AGENT_ID].asUUID().notNull()) - { - row[OWNER_ID]=row[AGENT_ID]; - } - else - { - row[OWNER_ID]=row[GROUP_ID]; - } - } - //signal signal_map_t::iterator sig_it = sSignalMap.find(public_key); if (sig_it != sSignalMap.end()) @@ -427,7 +410,7 @@ namespace LLExperienceCache int request_count = 0; while(!sAskQueue.empty() && request_count < sMaximumLookups) { - ask_queue_t::const_iterator it = sAskQueue.begin(); + ask_queue_t::iterator it = sAskQueue.begin(); const LLUUID& key = it->first; const std::string& key_type = it->second; -- cgit v1.2.3 From 74dcc04e69b845e62d25e83b615399f8a5d26d21 Mon Sep 17 00:00:00 2001 From: dolphin Date: Mon, 17 Mar 2014 15:57:15 -0700 Subject: Updated experience cache to get a const reference to xp data --- indra/llmessage/llexperiencecache.cpp | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) (limited to 'indra/llmessage/llexperiencecache.cpp') diff --git a/indra/llmessage/llexperiencecache.cpp b/indra/llmessage/llexperiencecache.cpp index 648e2039a6..c8deaac1ef 100644 --- a/indra/llmessage/llexperiencecache.cpp +++ b/indra/llmessage/llexperiencecache.cpp @@ -320,9 +320,9 @@ namespace LLExperienceCache for ( ; it != mKeys.end(); ++it) { - LLSD exp; + LLSD exp = get(it->first); //leave the properties alone if we already have a cache entry for this xp - if(!get(it->first, exp)) + if(exp.isUndefined()) { exp[PROPERTIES]=PROPERTY_INVALID; } @@ -563,24 +563,21 @@ namespace LLExperienceCache LL_WARNS("ExperienceCache") << ": Ignoring cache insert of experience which is missing " << EXPERIENCE_ID << LL_ENDL; } } - - bool get( const LLUUID& key, LLSD& experience_data ) + static LLSD empty; + const LLSD& get(const LLUUID& key) { - if(key.isNull()) return false; + if(key.isNull()) return empty; cache_t::const_iterator it = sCache.find(key); - + if (it != sCache.end()) { - experience_data = it->second; - return true; + return it->second; } - + fetch(key); - return false; + return empty; } - - void get( const LLUUID& key, callback_slot_t slot ) { if(key.isNull()) return; -- cgit v1.2.3 From c88b237473a75310722bac8d65a028a33a573215 Mon Sep 17 00:00:00 2001 From: Cho Date: Fri, 20 Jun 2014 04:19:45 +0100 Subject: Updated LLExperienceCache::LLExperienceResponder to work with updated LLCurl::Responder interface, to fix ACME-1532 and ACME-1525 --- indra/llmessage/llexperiencecache.cpp | 26 ++++++++++---------------- 1 file changed, 10 insertions(+), 16 deletions(-) (limited to 'indra/llmessage/llexperiencecache.cpp') diff --git a/indra/llmessage/llexperiencecache.cpp b/indra/llmessage/llexperiencecache.cpp index c8deaac1ef..1fb77c4391 100644 --- a/indra/llmessage/llexperiencecache.cpp +++ b/indra/llmessage/llexperiencecache.cpp @@ -257,7 +257,7 @@ namespace LLExperienceCache LLSDSerialize::toPrettyXML(data, ostr); } - class LLExperienceResponder : public LLHTTPClient::Responder + class LLExperienceResponder : public LLCurl::Responder { public: LLExperienceResponder(const ask_queue_t& keys) @@ -266,14 +266,9 @@ namespace LLExperienceCache } - virtual void completedHeader(U32 status, const std::string& reason, const LLSD& content) + /*virtual*/ void httpSuccess() { - mHeaders = content; - } - - virtual void result(const LLSD& content) - { - LLSD experiences = content["experience_keys"]; + LLSD experiences = getContent()["experience_keys"]; LLSD::array_const_iterator it = experiences.beginArray(); for( /**/ ; it != experiences.endArray(); ++it) { @@ -287,7 +282,7 @@ namespace LLExperienceCache processExperience(public_key, row); } - LLSD error_ids = content["error_ids"]; + LLSD error_ids = getContent()["error_ids"]; LLSD::array_const_iterator errIt = error_ids.beginArray(); for( /**/ ; errIt != error_ids.endArray() ; ++errIt ) { @@ -306,13 +301,13 @@ namespace LLExperienceCache LL_DEBUGS("ExperienceCache") << sCache.size() << " cached experiences" << LL_ENDL; } - virtual void error(U32 status, const std::string& reason) + /*virtual*/ void httpFailure() { - LL_WARNS("ExperienceCache") << "Request failed "<first; exp["key_type"] = it->second; exp["uuid"] = it->first; - exp["error"] = (LLSD::Integer)status; + exp["error"] = (LLSD::Integer)getStatus(); exp[QUOTA] = DEFAULT_QUOTA; LLExperienceCache::processExperience(it->first, exp); @@ -344,7 +339,7 @@ namespace LLExperienceCache { // Retry-After takes priority - LLSD retry_after = mHeaders["retry-after"]; + LLSD retry_after = getResponseHeaders()["retry-after"]; if (retry_after.isDefined()) { // We only support the delta-seconds type @@ -358,7 +353,7 @@ namespace LLExperienceCache // If no Retry-After, look for Cache-Control max-age F64 expires = 0.0; - if (LLExperienceCache::expirationFromCacheControl(mHeaders, &expires)) + if (LLExperienceCache::expirationFromCacheControl(getResponseHeaders(), &expires)) { return expires; } @@ -387,7 +382,6 @@ namespace LLExperienceCache private: ask_queue_t mKeys; - LLSD mHeaders; }; void requestExperiences() -- cgit v1.2.3 From 200788c344f5449f99eacc9167ac15c7e6262b69 Mon Sep 17 00:00:00 2001 From: Cho Date: Tue, 24 Jun 2014 22:43:23 +0100 Subject: Updated all experience responders for LLCurl::Responder interface changes for ACME-1535 and ACME-1536 --- indra/llmessage/llexperiencecache.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'indra/llmessage/llexperiencecache.cpp') diff --git a/indra/llmessage/llexperiencecache.cpp b/indra/llmessage/llexperiencecache.cpp index 1fb77c4391..52b60a176e 100644 --- a/indra/llmessage/llexperiencecache.cpp +++ b/indra/llmessage/llexperiencecache.cpp @@ -257,7 +257,7 @@ namespace LLExperienceCache LLSDSerialize::toPrettyXML(data, ostr); } - class LLExperienceResponder : public LLCurl::Responder + class LLExperienceResponder : public LLHTTPClient::Responder { public: LLExperienceResponder(const ask_queue_t& keys) @@ -266,7 +266,7 @@ namespace LLExperienceCache } - /*virtual*/ void httpSuccess() + /*virtual*/ void httpCompleted() { LLSD experiences = getContent()["experience_keys"]; LLSD::array_const_iterator it = experiences.beginArray(); -- cgit v1.2.3