diff options
Diffstat (limited to 'indra/newview/llmutelist.cpp')
| -rw-r--r-- | indra/newview/llmutelist.cpp | 202 |
1 files changed, 168 insertions, 34 deletions
diff --git a/indra/newview/llmutelist.cpp b/indra/newview/llmutelist.cpp index b7bba02b9d..b72301c566 100644 --- a/indra/newview/llmutelist.cpp +++ b/indra/newview/llmutelist.cpp @@ -92,7 +92,17 @@ public: const LLUUID& invoice, const sparam_t& strings) { - LLMuteList::getInstance()->setLoaded(); + // We've gotten a message from the server that indicates our mute list is empty there. + + // First we want to make sure that if we had a cached mute list, we clear it assuming it is outdated. + LLMuteList* mute_list = LLMuteList::getInstance(); + if(mute_list->mLoadSource == LLMuteList::MLS_FALLBACK_CACHE && !mute_list->getMutes().empty()) + { + LL_WARNS() << "Our current mute list is not empty, but the server says that it should be. Is our cache outdated, or did our mutes get lost?" << LL_ENDL; + mute_list->clearCachedMutes(); + } + // Lastly we set the load state to loaded with the source of server empty. We are now in a clean and ready state. + mute_list->setLoaded(LLMuteList::MLS_SERVER_EMPTY); return true; } }; @@ -155,7 +165,9 @@ std::string LLMute::getDisplayType() const //----------------------------------------------------------------------------- LLMuteList::LLMuteList() : mLoadState(ML_INITIAL), - mRequestStartTime(0.f) + mLoadSource(MLS_NONE), + mRequestStartTime(0.f), + mTriedCacheFallback(false) { gGenericDispatcher.addHandler("emptymutelist", &sDispatchEmptyMuteList); @@ -178,6 +190,8 @@ LLMuteList::LLMuteList() : // but this way is just more convinient onAccountNameChanged(id, av_name.getUserName()); }); + // Register our region change callback handler early, we'll clean it up if/when we don't need it anymore. + mRegionChangedCallback = gAgent.addRegionChangedCallback(boost::bind(&LLMuteList::onRegionChanged, this)); } //----------------------------------------------------------------------------- @@ -191,6 +205,10 @@ LLMuteList::~LLMuteList() void LLMuteList::cleanupSingleton() { LLAvatarNameCache::getInstance()->setAccountNameChangedCallback(nullptr); + if (mRegionChangedCallback.connected()) + { + mRegionChangedCallback.disconnect(); + } } bool LLMuteList::isLinden(const std::string& name) @@ -210,9 +228,9 @@ bool LLMuteList::isLinden(const std::string& name) return last_name == "linden"; } -bool LLMuteList::getLoadFailed() const +bool LLMuteList::updateLoadState() { - if (mLoadState == ML_FAILED) + if (isLoaded() || isFailed()) { return true; } @@ -221,9 +239,83 @@ bool LLMuteList::getLoadFailed() const constexpr F64 WAIT_SECONDS = 30; if (mRequestStartTime + WAIT_SECONDS < LLTimer::getTotalSeconds()) { - return true; + LL_WARNS() << "Mute list request timed out; trying cache fallback once" << LL_ENDL; + tryLoadCacheFallback(gAgent.getID(), "request timeout"); + return isLoaded() || isFailed(); + } + } + return false; +} + +void LLMuteList::clearCachedMutes() +{ + mMutes.clear(); + mLegacyMutes.clear(); + LL_WARNS() << "Cached mutes cleared" << LL_ENDL; +} + +const char* LLMuteList::sourceToString(EMuteListSource source) +{ + switch (source) + { + case MLS_NONE: + return "none"; + case MLS_SERVER: + return "server"; + case MLS_SERVER_EMPTY: + return "server-empty"; + case MLS_SERVER_CACHE: + return "server-cached"; + case MLS_FALLBACK_CACHE: + return "fallback-cache"; + default: + return "unknown"; + } +} + +std::string LLMuteList::getCacheFilename(const LLUUID& agent_id) const +{ + std::string agent_id_string; + agent_id.toString(agent_id_string); + return gDirUtilp->getExpandedFilename(LL_PATH_CACHE, agent_id_string) + ".cached_mute"; +} + +void LLMuteList::setFailed(const std::string& reason) +{ + mLoadState = ML_FAILED; + if (mLoadSource == MLS_NONE) + { + LL_WARNS() << "Mute list unavailable: " << reason << LL_ENDL; + } + else + { + LL_WARNS() << "Mute list unavailable: " << reason << " (last source=" << sourceToString(mLoadSource) << ")" << LL_ENDL; + } + notifyObservers(); +} + +bool LLMuteList::tryLoadCacheFallback(const LLUUID& agent_id, const std::string& reason) +{ + if (mTriedCacheFallback) + { + if (!isLoaded()) + { + setFailed("cache fallback already attempted before " + reason); } + return isLoaded(); } + + mTriedCacheFallback = true; + const std::string filename = getCacheFilename(agent_id); + LL_INFOS() << "Trying mute list cache fallback due to " << reason << ": " << filename << LL_ENDL; + + if (loadFromFile(filename, MLS_FALLBACK_CACHE)) + { + LL_WARNS() << "Loaded mute list from cache fallback due to " << reason << LL_ENDL; + return true; + } + + setFailed("cache fallback failed after " + reason); return false; } @@ -580,14 +672,14 @@ std::vector<LLMute> LLMuteList::getMutes() const //----------------------------------------------------------------------------- // loadFromFile() //----------------------------------------------------------------------------- -bool LLMuteList::loadFromFile(const std::string& filename) +bool LLMuteList::loadFromFile(const std::string& filename, EMuteListSource source) { LL_PROFILE_ZONE_SCOPED; if(!filename.size()) { LL_WARNS() << "Mute List Filename is Empty!" << LL_ENDL; - mLoadState = ML_FAILED; + setFailed("empty filename"); return false; } @@ -595,10 +687,13 @@ bool LLMuteList::loadFromFile(const std::string& filename) if (!fp) { LL_WARNS() << "Couldn't open mute list " << filename << LL_ENDL; - mLoadState = ML_FAILED; + setFailed("cannot open " + filename); return false; } + // Replace previous server-backed state so fallback can be superseded by authoritative data. + clearCachedMutes(); + // *NOTE: Changing the size of these buffers will require changes // in the scanf below. char id_buffer[MAX_STRING]; /*Flawfinder: ignore*/ @@ -627,7 +722,7 @@ bool LLMuteList::loadFromFile(const std::string& filename) } } fclose(fp); - setLoaded(); + setLoaded(source); // server does not maintain up-to date account names (not display names!) // in this list, so it falls to viewer. @@ -737,12 +832,16 @@ bool LLMuteList::isMuted(const std::string& username, U32 flags) const //----------------------------------------------------------------------------- void LLMuteList::requestFromServer(const LLUUID& agent_id) { - std::string agent_id_string; - std::string filename; - agent_id.toString(agent_id_string); - filename = gDirUtilp->getExpandedFilename(LL_PATH_CACHE,agent_id_string) + ".cached_mute"; + if(isLoadedFromServer()) + { + LL_WARNS() << "Blocked attempt to request mute list from server when already loaded from server!" << LL_ENDL; + return; + } + const std::string filename = getCacheFilename(agent_id); LLCRC crc; crc.update(filename); + mTriedCacheFallback = false; + mLoadSource = MLS_NONE; LLMessageSystem* msg = gMessageSystem; msg->newMessageFast(_PREHASH_MuteListRequest); @@ -755,17 +854,19 @@ void LLMuteList::requestFromServer(const LLUUID& agent_id) if (gDisconnected) { LL_WARNS() << "Trying to request mute list when disconnected!" << LL_ENDL; - mLoadState = ML_FAILED; + // Guard against potentially writing back to disk since we're not recovering our connection + mLoadState = ML_LOADED; + mLoadSource = MLS_FALLBACK_CACHE; return; } if (!gAgent.getRegion()) { LL_WARNS() << "No region for agent yet, skipping mute list request!" << LL_ENDL; - mLoadState = ML_FAILED; + tryLoadCacheFallback(agent_id, "no region for request"); return; } mLoadState = ML_REQUESTED; - mRequestStartTime = LLTimer::getElapsedSeconds(); + mRequestStartTime = LLTimer::getTotalSeconds(); // Double amount of retries due to this request happening during busy stage // Ideally this should be turned into a capability gMessageSystem->sendReliable(gAgent.getRegionHost(), LL_DEFAULT_RELIABLE_RETRIES * 2, true, LL_PING_BASED_TIMEOUT_DUMMY, NULL, NULL); @@ -777,15 +878,16 @@ void LLMuteList::requestFromServer(const LLUUID& agent_id) void LLMuteList::cache(const LLUUID& agent_id) { - // Write to disk even if empty. - if(isLoaded()) + // Write to disk even if empty, but never from degraded fallback state. + if (isLoaded() && mLoadSource != MLS_FALLBACK_CACHE) { - std::string agent_id_string; - std::string filename; - agent_id.toString(agent_id_string); - filename = gDirUtilp->getExpandedFilename(LL_PATH_CACHE,agent_id_string) + ".cached_mute"; + const std::string filename = getCacheFilename(agent_id); saveToFile(filename); } + else if (isLoaded()) + { + LL_WARNS() << "Skipping mute list cache write from fallback-only state" << LL_ENDL; + } } //----------------------------------------------------------------------------- @@ -795,11 +897,16 @@ void LLMuteList::cache(const LLUUID& agent_id) void LLMuteList::processMuteListUpdate(LLMessageSystem* msg, void**) { LL_INFOS() << "LLMuteList::processMuteListUpdate()" << LL_ENDL; + LLMuteList* mute_list = getInstance(); + if(mute_list->mTriedRegionChangeRetry) + { + LL_WARNS() << "Received mute list update after retrying region change; success!" << LL_ENDL; + } LLUUID agent_id; msg->getUUIDFast(_PREHASH_MuteData, _PREHASH_AgentID, agent_id); if(agent_id != gAgent.getID()) { - LL_WARNS() << "Got an mute list update for the wrong agent." << LL_ENDL; + LL_WARNS() << "Got a mute list update for the wrong agent." << LL_ENDL; return; } std::string unclean_filename; @@ -810,9 +917,8 @@ void LLMuteList::processMuteListUpdate(LLMessageSystem* msg, void**) LL_WARNS() << "Received empty mute list filename." << LL_ENDL; } - LLMuteList* mute_list = getInstance(); mute_list->mLoadState = ML_REQUESTED; - mute_list->mRequestStartTime = LLTimer::getElapsedSeconds(); + mute_list->mRequestStartTime = LLTimer::getTotalSeconds(); // Todo: Based of logs and testing, there is no callback // from server if file doesn't exist server side. @@ -831,12 +937,12 @@ void LLMuteList::processMuteListUpdate(LLMessageSystem* msg, void**) void LLMuteList::processUseCachedMuteList(LLMessageSystem* msg, void**) { LL_INFOS() << "LLMuteList::processUseCachedMuteList()" << LL_ENDL; - - std::string agent_id_string; - gAgent.getID().toString(agent_id_string); - std::string filename; - filename = gDirUtilp->getExpandedFilename(LL_PATH_CACHE,agent_id_string) + ".cached_mute"; - LLMuteList::getInstance()->loadFromFile(filename); + LLMuteList* mute_list = LLMuteList::getInstance(); + if(mute_list->mTriedRegionChangeRetry) + { + LL_WARNS() << "Received use cached mute list message after retrying region change; success!" << LL_ENDL; + } + mute_list->loadFromFile(mute_list->getCacheFilename(gAgent.getID()), MLS_SERVER_CACHE); } void LLMuteList::onFileMuteList(void** user_data, S32 error_code, LLExtStat ext_status) @@ -845,13 +951,13 @@ void LLMuteList::onFileMuteList(void** user_data, S32 error_code, LLExtStat ext_ if(local_filename_and_path && !local_filename_and_path->empty() && (error_code == 0)) { LL_INFOS() << "Received mute list from server" << LL_ENDL; - LLMuteList::getInstance()->loadFromFile(*local_filename_and_path); + LLMuteList::getInstance()->loadFromFile(*local_filename_and_path, MLS_SERVER); LLFile::remove(*local_filename_and_path); } else { LL_INFOS() << "LLMuteList xfer failed with code " << error_code << LL_ENDL; - LLMuteList::getInstance()->mLoadState = ML_FAILED; + LLMuteList::getInstance()->tryLoadCacheFallback(gAgent.getID(), "xfer failure"); } delete local_filename_and_path; } @@ -908,10 +1014,21 @@ void LLMuteList::removeObserver(LLMuteListObserver* observer) mObservers.erase(observer); } -void LLMuteList::setLoaded() +void LLMuteList::setLoaded(EMuteListSource source) { + if(isLoaded()) + { + LL_WARNS() << "Mute list was already loaded from " << sourceToString(mLoadSource) << ", switching to " << sourceToString(source) << LL_ENDL; + } mLoadState = ML_LOADED; + mLoadSource = source; notifyObservers(); + LL_INFOS() << "Mute list loaded from " << sourceToString(source) << LL_ENDL; + if(isLoadedFromServer() && mRegionChangedCallback.connected()) + { + LL_INFOS() << "Mute list loaded from server, disconnecting region change callback" << LL_ENDL; + mRegionChangedCallback.disconnect(); + } } void LLMuteList::notifyObservers() @@ -940,6 +1057,23 @@ void LLMuteList::notifyObserversDetailed(const LLMute& mute) } } +void LLMuteList::onRegionChanged() +{ + // If we are in a degraded state, either some protocol messages got lost between us and our login region, or our login region was having a bad day. + // Since the previous region might've been unable to provide our mute list, we can try to request it again from our new region. + // This is limited to one retry per session. + if(isLoadedDegraded() && !mTriedRegionChangeRetry) + { + if(mRegionChangedCallback.connected()) + { + mRegionChangedCallback.disconnect(); + } + LL_WARNS() << "Region changed while mute list is in degraded state, queueing a retry of the mute list request" << LL_ENDL; + mTriedRegionChangeRetry = true; + requestFromServer(gAgent.getID()); + } +} + LLRenderMuteList::LLRenderMuteList() {} |
