summaryrefslogtreecommitdiff
path: root/indra/newview/llmutelist.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'indra/newview/llmutelist.cpp')
-rw-r--r--indra/newview/llmutelist.cpp202
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()
{}