SL-14975 SL-14384 viewer crashes because of large chat groups
1. Due to desync participant can be NULL - added NULL checks 2. With large backlog of events, closing and then opening a goup session was causing a crash due to obsolete events - added cleanup for backlog 3. In some cases events were accumulating faster than they were processed - ensured that after certain point event processing scales up with a backlogmaster
parent
a1d2b94b4c
commit
9505e14efe
|
|
@ -355,7 +355,7 @@ LLConversationItemParticipant* LLConversationItemSession::findParticipant(const
|
|||
for (iter = mChildren.begin(); iter != mChildren.end(); iter++)
|
||||
{
|
||||
participant = dynamic_cast<LLConversationItemParticipant*>(*iter);
|
||||
if (participant->hasSameValue(participant_id))
|
||||
if (participant && participant->hasSameValue(participant_id))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
|
@ -466,7 +466,7 @@ const bool LLConversationItemSession::getTime(F64& time) const
|
|||
{
|
||||
participant = dynamic_cast<LLConversationItemParticipant*>(*iter);
|
||||
F64 participant_time;
|
||||
if (participant->getTime(participant_time))
|
||||
if (participant && participant->getTime(participant_time))
|
||||
{
|
||||
has_time = true;
|
||||
most_recent_time = llmax(most_recent_time,participant_time);
|
||||
|
|
|
|||
|
|
@ -617,10 +617,13 @@ void LLConversationViewParticipant::refresh()
|
|||
{
|
||||
// Refresh the participant view from its model data
|
||||
LLConversationItemParticipant* participant_model = dynamic_cast<LLConversationItemParticipant*>(getViewModelItem());
|
||||
participant_model->resetRefresh();
|
||||
|
||||
// *TODO: We should also do something with vmi->isModerator() to echo that state in the UI somewhat
|
||||
mSpeakingIndicator->setIsModeratorMuted(participant_model->isModeratorMuted());
|
||||
if (participant_model)
|
||||
{
|
||||
participant_model->resetRefresh();
|
||||
|
||||
// *TODO: We should also do something with vmi->isModerator() to echo that state in the UI somewhat
|
||||
mSpeakingIndicator->setIsModeratorMuted(participant_model->isModeratorMuted());
|
||||
}
|
||||
|
||||
// Do the regular upstream refresh
|
||||
LLFolderViewItem::refresh();
|
||||
|
|
|
|||
|
|
@ -59,7 +59,9 @@
|
|||
#include "boost/foreach.hpp"
|
||||
|
||||
|
||||
const S32 EVENTS_PER_IDLE_LOOP = 100;
|
||||
const S32 EVENTS_PER_IDLE_LOOP_CURRENT_SESSION = 80;
|
||||
const S32 EVENTS_PER_IDLE_LOOP_BACKGROUND = 40;
|
||||
const F32 EVENTS_PER_IDLE_LOOP_MIN_PERCENTAGE = 0.01f; // process a minimum of 1% of total events per frame
|
||||
|
||||
//
|
||||
// LLFloaterIMContainer
|
||||
|
|
@ -416,8 +418,11 @@ void LLFloaterIMContainer::processParticipantsStyleUpdate()
|
|||
while (current_participant_model != end_participant_model)
|
||||
{
|
||||
LLConversationItemParticipant* participant_model = dynamic_cast<LLConversationItemParticipant*>(*current_participant_model);
|
||||
// Get the avatar name for this participant id from the cache and update the model
|
||||
participant_model->updateName();
|
||||
if (participant_model)
|
||||
{
|
||||
// Get the avatar name for this participant id from the cache and update the model
|
||||
participant_model->updateName();
|
||||
}
|
||||
// Next participant
|
||||
current_participant_model++;
|
||||
}
|
||||
|
|
@ -464,8 +469,11 @@ void LLFloaterIMContainer::idleUpdate()
|
|||
while (current_participant_model != end_participant_model)
|
||||
{
|
||||
LLConversationItemParticipant* participant_model = dynamic_cast<LLConversationItemParticipant*>(*current_participant_model);
|
||||
participant_model->setModeratorOptionsVisible(is_moderator);
|
||||
participant_model->setGroupBanVisible(can_ban && participant_model->getUUID() != gAgentID);
|
||||
if (participant_model)
|
||||
{
|
||||
participant_model->setModeratorOptionsVisible(is_moderator);
|
||||
participant_model->setGroupBanVisible(can_ban && participant_model->getUUID() != gAgentID);
|
||||
}
|
||||
|
||||
current_participant_model++;
|
||||
}
|
||||
|
|
@ -498,20 +506,49 @@ void LLFloaterIMContainer::idleUpdate()
|
|||
|
||||
void LLFloaterIMContainer::idleProcessEvents()
|
||||
{
|
||||
if (!mConversationEventQueue.empty())
|
||||
{
|
||||
S32 events_to_handle = llmin((S32)mConversationEventQueue.size(), EVENTS_PER_IDLE_LOOP);
|
||||
for (S32 i = 0; i < events_to_handle; i++)
|
||||
{
|
||||
handleConversationModelEvent(mConversationEventQueue.back());
|
||||
mConversationEventQueue.pop_back();
|
||||
}
|
||||
}
|
||||
LLUUID current_session_id = getSelectedSession();
|
||||
conversations_items_deque::iterator iter = mConversationEventQueue.begin();
|
||||
conversations_items_deque::iterator end = mConversationEventQueue.end();
|
||||
while (iter != end)
|
||||
{
|
||||
std::deque<LLSD> &events = iter->second;
|
||||
if (!events.empty())
|
||||
{
|
||||
S32 events_to_handle;
|
||||
S32 query_size = (S32)events.size();
|
||||
if (current_session_id == iter->first)
|
||||
{
|
||||
events_to_handle = EVENTS_PER_IDLE_LOOP_CURRENT_SESSION;
|
||||
}
|
||||
else
|
||||
{
|
||||
events_to_handle = EVENTS_PER_IDLE_LOOP_BACKGROUND;
|
||||
}
|
||||
|
||||
if (events_to_handle <= query_size)
|
||||
{
|
||||
// Some groups can be very large and can generate huge amount of updates, scale processing up to keep up
|
||||
events_to_handle = llmax(events_to_handle, (S32)(query_size * EVENTS_PER_IDLE_LOOP_MIN_PERCENTAGE));
|
||||
}
|
||||
else
|
||||
{
|
||||
events_to_handle = query_size;
|
||||
}
|
||||
|
||||
for (S32 i = 0; i < events_to_handle; i++)
|
||||
{
|
||||
handleConversationModelEvent(events.back());
|
||||
events.pop_back();
|
||||
}
|
||||
}
|
||||
iter++;
|
||||
}
|
||||
}
|
||||
|
||||
bool LLFloaterIMContainer::onConversationModelEvent(const LLSD& event)
|
||||
{
|
||||
mConversationEventQueue.push_front(event);
|
||||
LLUUID id = event.get("session_uuid").asUUID();
|
||||
mConversationEventQueue[id].push_front(event);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -1822,6 +1859,8 @@ bool LLFloaterIMContainer::removeConversationListItem(const LLUUID& uuid, bool c
|
|||
// Suppress the conversation items and widgets from their respective maps
|
||||
mConversationsItems.erase(uuid);
|
||||
mConversationsWidgets.erase(uuid);
|
||||
// Clear event query (otherwise reopening session in some way can bombard session with stale data)
|
||||
mConversationEventQueue.erase(uuid);
|
||||
|
||||
// Don't let the focus fall IW, select and refocus on the first conversation in the list
|
||||
if (change_focus)
|
||||
|
|
|
|||
|
|
@ -229,9 +229,10 @@ private:
|
|||
conversations_widgets_map mConversationsWidgets;
|
||||
LLConversationViewModel mConversationViewModel;
|
||||
LLFolderView* mConversationsRoot;
|
||||
LLEventStream mConversationsEventStream;
|
||||
LLEventStream mConversationsEventStream;
|
||||
|
||||
std::deque<LLSD> mConversationEventQueue;
|
||||
typedef std::map<LLUUID, std::deque<LLSD> > conversations_items_deque;
|
||||
conversations_items_deque mConversationEventQueue;
|
||||
|
||||
LLTimer mParticipantRefreshTimer;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -492,7 +492,10 @@ void LLFloaterIMSessionTab::buildConversationViewParticipant()
|
|||
while (current_participant_model != end_participant_model)
|
||||
{
|
||||
LLConversationItem* participant_model = dynamic_cast<LLConversationItem*>(*current_participant_model);
|
||||
addConversationViewParticipant(participant_model);
|
||||
if (participant_model)
|
||||
{
|
||||
addConversationViewParticipant(participant_model);
|
||||
}
|
||||
current_participant_model++;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue