summaryrefslogtreecommitdiff
path: root/indra/newview
diff options
context:
space:
mode:
Diffstat (limited to 'indra/newview')
-rw-r--r--indra/newview/llfloateravatarpicker.cpp9
-rwxr-xr-xindra/newview/llinventorymodel.cpp197
-rwxr-xr-xindra/newview/llinventorymodel.h4
-rwxr-xr-x[-rw-r--r--]indra/newview/llinventorymodelbackgroundfetch.cpp2
-rw-r--r--indra/newview/llviewerobject.cpp36
-rw-r--r--indra/newview/llviewerobject.h2
-rwxr-xr-xindra/newview/llvoavatar.cpp29
7 files changed, 251 insertions, 28 deletions
diff --git a/indra/newview/llfloateravatarpicker.cpp b/indra/newview/llfloateravatarpicker.cpp
index 08f08a0cb0..0844a70e25 100644
--- a/indra/newview/llfloateravatarpicker.cpp
+++ b/indra/newview/llfloateravatarpicker.cpp
@@ -819,7 +819,14 @@ bool LLFloaterAvatarPicker::isSelectBtnEnabled()
uuid_vec_t avatar_ids;
std::vector<LLAvatarName> avatar_names;
getSelectedAvatarData(list, avatar_ids, avatar_names);
- return mOkButtonValidateSignal(avatar_ids);
+ if (avatar_ids.size() >= 1)
+ {
+ ret_val = mOkButtonValidateSignal(avatar_ids);
+ }
+ else
+ {
+ ret_val = false;
+ }
}
}
diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp
index ae8efeecda..f60fd63eee 100755
--- a/indra/newview/llinventorymodel.cpp
+++ b/indra/newview/llinventorymodel.cpp
@@ -252,6 +252,23 @@ const LLViewerInventoryCategory* LLInventoryModel::getFirstDescendantOf(const LL
return NULL;
}
+bool LLInventoryModel::getObjectTopmostAncestor(const LLUUID& object_id, LLUUID& result) const
+{
+ LLInventoryObject *object = getObject(object_id);
+ while (object && object->getParentUUID().notNull())
+ {
+ LLInventoryObject *parent_object = getObject(object->getParentUUID());
+ if (!parent_object)
+ {
+ llwarns << "unable to trace topmost ancestor, missing item for uuid " << object->getParentUUID() << llendl;
+ return false;
+ }
+ object = parent_object;
+ }
+ result = object->getUUID();
+ return true;
+}
+
// Get the object by id. Returns NULL if not found.
LLInventoryObject* LLInventoryModel::getObject(const LLUUID& id) const
{
@@ -2083,7 +2100,7 @@ void LLInventoryModel::buildParentChildMap()
// implement it, we would need a set or map of uuid pairs
// which would be (folder_id, new_parent_id) to be sent up
// to the server.
- llinfos << "Lost categroy: " << cat->getUUID() << " - "
+ llinfos << "Lost category: " << cat->getUUID() << " - "
<< cat->getName() << llendl;
++lost;
// plop it into the lost & found.
@@ -2102,6 +2119,8 @@ void LLInventoryModel::buildParentChildMap()
// it's a protected folder.
cat->setParent(gInventory.getRootFolderID());
}
+ // FIXME note that updateServer() fails with protected
+ // types, so this will not work as intended in that case.
cat->updateServer(TRUE);
catsp = getUnlockedCatArray(cat->getParentUUID());
if(catsp)
@@ -2247,6 +2266,11 @@ void LLInventoryModel::buildParentChildMap()
notifyObservers();
}
}
+
+ //if (!gInventory.validate())
+ //{
+ // llwarns << "model failed validity check!" << llendl;
+ //}
}
struct LLUUIDAndName
@@ -2917,6 +2941,9 @@ void LLInventoryModel::processBulkUpdateInventory(LLMessageSystem* msg, void**)
InventoryCallbackInfo cbinfo = (*inv_it);
gInventoryCallbacks.fire(cbinfo.mCallback, cbinfo.mInvID);
}
+
+ //gInventory.validate();
+
// Don't show the inventory. We used to call showAgentInventory here.
//LLFloaterInventory* view = LLFloaterInventory::getActiveInventory();
//if(view)
@@ -3363,6 +3390,174 @@ void LLInventoryModel::dumpInventory() const
llinfos << "\n**********************\nEnd Inventory Dump" << llendl;
}
+// Do various integrity checks on model, logging issues found and
+// returning an overall good/bad flag.
+bool LLInventoryModel::validate() const
+{
+ bool valid = true;
+
+ if (getRootFolderID().isNull())
+ {
+ llwarns << "no root folder id" << llendl;
+ valid = false;
+ }
+ if (getLibraryRootFolderID().isNull())
+ {
+ llwarns << "no root folder id" << llendl;
+ valid = false;
+ }
+
+ if (mCategoryMap.size() + 1 != mParentChildCategoryTree.size())
+ {
+ // ParentChild should be one larger because of the special entry for null uuid.
+ llinfos << "unexpected sizes: cat map size " << mCategoryMap.size()
+ << " parent/child " << mParentChildCategoryTree.size() << llendl;
+ valid = false;
+ }
+ S32 cat_lock = 0;
+ S32 item_lock = 0;
+ S32 desc_unknown_count = 0;
+ S32 version_unknown_count = 0;
+ for(cat_map_t::const_iterator cit = mCategoryMap.begin(); cit != mCategoryMap.end(); ++cit)
+ {
+ const LLUUID& cat_id = cit->first;
+ const LLViewerInventoryCategory *cat = cit->second;
+ if (!cat)
+ {
+ llwarns << "invalid cat" << llendl;
+ valid = false;
+ continue;
+ }
+ if (cat_id != cat->getUUID())
+ {
+ llwarns << "cat id/index mismatch " << cat_id << " " << cat->getUUID() << llendl;
+ valid = false;
+ }
+
+ if (cat->getParentUUID().isNull())
+ {
+ if (cat_id != getRootFolderID() && cat_id != getLibraryRootFolderID())
+ {
+ llwarns << "cat " << cat_id << " has no parent, but is not root ("
+ << getRootFolderID() << ") or library root ("
+ << getLibraryRootFolderID() << ")" << llendl;
+ }
+ }
+ cat_array_t* cats;
+ item_array_t* items;
+ getDirectDescendentsOf(cat_id,cats,items);
+ if (!cats || !items)
+ {
+ llwarns << "invalid direct descendents for " << cat_id << llendl;
+ valid = false;
+ continue;
+ }
+ if (cat->getDescendentCount() == LLViewerInventoryCategory::DESCENDENT_COUNT_UNKNOWN)
+ {
+ desc_unknown_count++;
+ }
+ else if (cats->size() + items->size() != cat->getDescendentCount())
+ {
+ llwarns << "invalid desc count for " << cat_id << " name " << cat->getName()
+ << " cached " << cat->getDescendentCount()
+ << " expected " << cats->size() << "+" << items->size()
+ << "=" << cats->size() +items->size() << llendl;
+ valid = false;
+ }
+ if (cat->getVersion() == LLViewerInventoryCategory::VERSION_UNKNOWN)
+ {
+ version_unknown_count++;
+ }
+ if (mCategoryLock.count(cat_id))
+ {
+ cat_lock++;
+ }
+ if (mItemLock.count(cat_id))
+ {
+ item_lock++;
+ }
+ for (S32 i = 0; i<items->size(); i++)
+ {
+ LLViewerInventoryItem *item = items->get(i);
+
+ if (!item)
+ {
+ llwarns << "null item at index " << i << " for cat " << cat_id << llendl;
+ valid = false;
+ continue;
+ }
+
+ const LLUUID& item_id = item->getUUID();
+
+ if (item->getParentUUID() != cat_id)
+ {
+ llwarns << "wrong parent for " << item_id << " found "
+ << item->getParentUUID() << " expected " << cat_id
+ << llendl;
+ valid = false;
+ }
+
+
+ // Entries in items and mItemMap should correspond.
+ item_map_t::const_iterator it = mItemMap.find(item_id);
+ if (it == mItemMap.end())
+ {
+ llwarns << "item " << item_id << " found as child of "
+ << cat_id << " but not in top level mItemMap" << llendl;
+ valid = false;
+ }
+ else
+ {
+ LLViewerInventoryItem *top_item = it->second;
+ if (top_item != item)
+ {
+ llwarns << "item mismatch, item_id " << item_id
+ << " top level entry is different, uuid " << top_item->getUUID() << llendl;
+ }
+ }
+
+ // Topmost ancestor should be root or library.
+ LLUUID topmost_ancestor_id;
+ bool found = getObjectTopmostAncestor(item_id, topmost_ancestor_id);
+ if (!found)
+ {
+ llwarns << "unable to find topmost ancestor for " << item_id << llendl;
+ valid = false;
+ }
+ else
+ {
+ if (topmost_ancestor_id != getRootFolderID() &&
+ topmost_ancestor_id != getLibraryRootFolderID())
+ {
+ llwarns << "unrecognized top level ancestor for " << item_id
+ << " got " << topmost_ancestor_id
+ << " expected " << getRootFolderID()
+ << " or " << getLibraryRootFolderID() << llendl;
+ valid = false;
+ }
+ }
+ }
+
+ }
+ if (cat_lock > 0 || item_lock > 0)
+ {
+ llwarns << "Found locks on some categories: sub-cat arrays "
+ << cat_lock << ", item arrays " << item_lock << llendl;
+ }
+ if (desc_unknown_count != 0)
+ {
+ llinfos << "Found " << desc_unknown_count << " cats with unknown descendent count" << llendl;
+ }
+ if (version_unknown_count != 0)
+ {
+ llinfos << "Found " << version_unknown_count << " cats with unknown version" << llendl;
+ }
+
+ llinfos << "Validate done, valid = " << (U32) valid << llendl;
+
+ return valid;
+}
+
///----------------------------------------------------------------------------
/// Local function definitions
///----------------------------------------------------------------------------
diff --git a/indra/newview/llinventorymodel.h b/indra/newview/llinventorymodel.h
index b7e1888f20..2459f10a37 100755
--- a/indra/newview/llinventorymodel.h
+++ b/indra/newview/llinventorymodel.h
@@ -227,6 +227,9 @@ public:
// Check if one object has a parent chain up to the category specified by UUID.
BOOL isObjectDescendentOf(const LLUUID& obj_id, const LLUUID& cat_id) const;
+ // Follow parent chain to the top.
+ bool getObjectTopmostAncestor(const LLUUID& object_id, LLUUID& result) const;
+
//--------------------------------------------------------------------
// Find
//--------------------------------------------------------------------
@@ -551,6 +554,7 @@ private:
//--------------------------------------------------------------------
public:
void dumpInventory() const;
+ bool validate() const;
/** Miscellaneous
** **
diff --git a/indra/newview/llinventorymodelbackgroundfetch.cpp b/indra/newview/llinventorymodelbackgroundfetch.cpp
index 01b0e647a9..4eeb528c66 100644..100755
--- a/indra/newview/llinventorymodelbackgroundfetch.cpp
+++ b/indra/newview/llinventorymodelbackgroundfetch.cpp
@@ -172,6 +172,8 @@ void LLInventoryModelBackgroundFetch::setAllFoldersFetched()
mRecursiveLibraryFetchStarted)
{
mAllFoldersFetched = TRUE;
+ //llinfos << "All folders fetched, validating" << llendl;
+ //gInventory.validate();
}
mFolderFetchActive = false;
}
diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp
index fcf5af76ff..670272e7be 100644
--- a/indra/newview/llviewerobject.cpp
+++ b/indra/newview/llviewerobject.cpp
@@ -2697,24 +2697,33 @@ void LLViewerObject::processTaskInvFile(void** user_data, S32 error_code, LLExtS
if(ft && (0 == error_code) &&
(object = gObjectList.findObject(ft->mTaskID)))
{
- object->loadTaskInvFile(ft->mFilename);
+ if (object->loadTaskInvFile(ft->mFilename))
+ {
- LLInventoryObject::object_list_t::iterator it = object->mInventory->begin();
- LLInventoryObject::object_list_t::iterator end = object->mInventory->end();
- std::list<LLUUID>& pending_lst = object->mPendingInventoryItemsIDs;
+ LLInventoryObject::object_list_t::iterator it = object->mInventory->begin();
+ LLInventoryObject::object_list_t::iterator end = object->mInventory->end();
+ std::list<LLUUID>& pending_lst = object->mPendingInventoryItemsIDs;
- for (; it != end && pending_lst.size(); ++it)
- {
- LLViewerInventoryItem* item = dynamic_cast<LLViewerInventoryItem*>(it->get());
- if(item && item->getType() != LLAssetType::AT_CATEGORY)
+ for (; it != end && pending_lst.size(); ++it)
{
- std::list<LLUUID>::iterator id_it = std::find(pending_lst.begin(), pending_lst.begin(), item->getAssetUUID());
- if (id_it != pending_lst.end())
+ LLViewerInventoryItem* item = dynamic_cast<LLViewerInventoryItem*>(it->get());
+ if(item && item->getType() != LLAssetType::AT_CATEGORY)
{
- pending_lst.erase(id_it);
+ std::list<LLUUID>::iterator id_it = std::find(pending_lst.begin(), pending_lst.begin(), item->getAssetUUID());
+ if (id_it != pending_lst.end())
+ {
+ pending_lst.erase(id_it);
+ }
}
}
}
+ else
+ {
+ // MAINT-2597 - crash when trying to edit a no-mod object
+ // Somehow get an contents inventory response, but with an invalid stream (possibly 0 size?)
+ // Stated repro was specific to no-mod objects so failing without user interaction should be safe.
+ llwarns << "Trying to load invalid task inventory file. Ignoring file contents." << llendl;
+ }
}
else
{
@@ -2726,7 +2735,7 @@ void LLViewerObject::processTaskInvFile(void** user_data, S32 error_code, LLExtS
delete ft;
}
-void LLViewerObject::loadTaskInvFile(const std::string& filename)
+BOOL LLViewerObject::loadTaskInvFile(const std::string& filename)
{
std::string filename_and_local_path = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, filename);
llifstream ifs(filename_and_local_path);
@@ -2773,8 +2782,11 @@ void LLViewerObject::loadTaskInvFile(const std::string& filename)
{
llwarns << "unable to load task inventory: " << filename_and_local_path
<< llendl;
+ return FALSE;
}
doInventoryCallback();
+
+ return TRUE;
}
void LLViewerObject::doInventoryCallback()
diff --git a/indra/newview/llviewerobject.h b/indra/newview/llviewerobject.h
index 728d279c39..316dbce7d0 100644
--- a/indra/newview/llviewerobject.h
+++ b/indra/newview/llviewerobject.h
@@ -656,7 +656,7 @@ protected:
//
static void processTaskInvFile(void** user_data, S32 error_code, LLExtStat ext_status);
- void loadTaskInvFile(const std::string& filename);
+ BOOL loadTaskInvFile(const std::string& filename);
void doInventoryCallback();
BOOL isOnMap();
diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp
index a56e09cde0..969106cceb 100755
--- a/indra/newview/llvoavatar.cpp
+++ b/indra/newview/llvoavatar.cpp
@@ -802,14 +802,14 @@ void LLVOAvatar::debugAvatarRezTime(std::string notification_name, std::string c
//------------------------------------------------------------------------
LLVOAvatar::~LLVOAvatar()
{
- if (!mFullyLoaded)
- {
+ if (!mFullyLoaded)
+ {
debugAvatarRezTime("AvatarRezLeftCloudNotification","left after ruth seconds as cloud");
- }
- else
- {
+ }
+ else
+ {
debugAvatarRezTime("AvatarRezLeftNotification","left sometime after declouding");
- }
+ }
logPendingPhases();
@@ -6029,6 +6029,11 @@ void LLVOAvatar::stopPhase(const std::string& phase_name, bool err_check)
void LLVOAvatar::logPendingPhases()
{
+ if (!isAgentAvatarValid())
+ {
+ return;
+ }
+
for (LLViewerStats::phase_map_t::iterator it = getPhases().begin();
it != getPhases().end();
++it)
@@ -6063,6 +6068,11 @@ void LLVOAvatar::logPendingPhasesAllAvatars()
void LLVOAvatar::logMetricsTimerRecord(const std::string& phase_name, F32 elapsed, bool completed)
{
+ if (!isAgentAvatarValid())
+ {
+ return;
+ }
+
LLSD record;
record["timer_name"] = phase_name;
record["avatar_id"] = getID();
@@ -6079,13 +6089,6 @@ void LLVOAvatar::logMetricsTimerRecord(const std::string& phase_name, F32 elapse
record["is_using_server_bakes"] = ((bool) isUsingServerBakes());
record["is_self"] = isSelf();
-
-#if 0 // verbose logging
- std::ostringstream ostr;
- ostr << LLSDNotationStreamer(record);
- LL_DEBUGS("Avatar") << "record\n" << ostr.str() << llendl;
-#endif
-
if (isAgentAvatarValid())
{
gAgentAvatarp->addMetricsTimerRecord(record);