summaryrefslogtreecommitdiff
path: root/indra/newview/llinventorymodel.cpp
diff options
context:
space:
mode:
authorAndrey Lihatskiy <alihatskiy@productengine.com>2022-04-18 20:38:56 +0300
committerAndrey Lihatskiy <alihatskiy@productengine.com>2022-04-18 20:38:56 +0300
commit16494f4400622adce8faaab54ac4f0d40e4ae0a5 (patch)
treec9e437df4b2142fdd0e2c865a930688f4e650d6b /indra/newview/llinventorymodel.cpp
parent651610d7541ec92d7e076860f07f6a585660fb71 (diff)
parentd031662435d97101411ae990ed85d6e001ab668a (diff)
Merge branch 'master' into DRTVWR-548-maint-N
Diffstat (limited to 'indra/newview/llinventorymodel.cpp')
-rw-r--r--indra/newview/llinventorymodel.cpp192
1 files changed, 140 insertions, 52 deletions
diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp
index b4fc832596..37500176ea 100644
--- a/indra/newview/llinventorymodel.cpp
+++ b/indra/newview/llinventorymodel.cpp
@@ -138,6 +138,8 @@ bool LLCanCache::operator()(LLInventoryCategory* cat, LLInventoryItem* item)
LLInventoryValidationInfo::LLInventoryValidationInfo():
mFatalErrorCount(0),
mWarningCount(0),
+ mLoopCount(0),
+ mOrphanedCount(0),
mInitialized(false),
mFatalNoRootFolder(false),
mFatalNoLibraryRootFolder(false),
@@ -147,7 +149,10 @@ LLInventoryValidationInfo::LLInventoryValidationInfo():
void LLInventoryValidationInfo::toOstream(std::ostream& os) const
{
- os << "mFatalErrorCount " << mFatalErrorCount << " mWarningCount " << mWarningCount;
+ os << "mFatalErrorCount " << mFatalErrorCount
+ << " mWarningCount " << mWarningCount
+ << " mLoopCount " << mLoopCount
+ << " mOrphanedCount " << mOrphanedCount;
}
@@ -161,6 +166,8 @@ void LLInventoryValidationInfo::asLLSD(LLSD& sd) const
{
sd["fatal_error_count"] = mFatalErrorCount;
sd["warning_count"] = mWarningCount;
+ sd["loop_count"] = mLoopCount;
+ sd["orphaned_count"] = mOrphanedCount;
sd["initialized"] = mInitialized;
sd["missing_system_folders_count"] = LLSD::Integer(mMissingRequiredSystemFolders.size());
sd["fatal_no_root_folder"] = mFatalNoRootFolder;
@@ -337,21 +344,35 @@ const LLViewerInventoryCategory* LLInventoryModel::getFirstDescendantOf(const LL
return NULL;
}
-bool LLInventoryModel::getObjectTopmostAncestor(const LLUUID& object_id, LLUUID& result) const
+LLInventoryModel::EAnscestorResult 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 (!object)
+ {
+ LL_WARNS(LOG_INV) << "Unable to trace topmost ancestor, initial object " << object_id << " does not exist" << LL_ENDL;
+ return ANSCESTOR_MISSING;
+ }
+
+ std::set<LLUUID> object_ids{ object_id }; // loop protection
+ while (object->getParentUUID().notNull())
+ {
+ LLUUID parent_id = object->getParentUUID();
+ if (object_ids.find(parent_id) != object_ids.end())
+ {
+ LL_WARNS(LOG_INV) << "Detected a loop on an object " << parent_id << " when searching for ancestor of " << object_id << LL_ENDL;
+ return ANSCESTOR_LOOP;
+ }
+ object_ids.insert(parent_id);
+ LLInventoryObject *parent_object = getObject(parent_id);
if (!parent_object)
{
- LL_WARNS(LOG_INV) << "unable to trace topmost ancestor, missing item for uuid " << object->getParentUUID() << LL_ENDL;
- return false;
+ LL_WARNS(LOG_INV) << "unable to trace topmost ancestor of " << object_id << ", missing item for uuid " << parent_id << LL_ENDL;
+ return ANSCESTOR_MISSING;
}
object = parent_object;
}
result = object->getUUID();
- return true;
+ return ANSCESTOR_OK;
}
// Get the object by id. Returns NULL if not found.
@@ -2947,42 +2968,69 @@ bool LLInventoryModel::saveToFile(const std::string& filename,
LL_INFOS(LOG_INV) << "saving inventory to: (" << filename << ")" << LL_ENDL;
- llofstream fileXML(filename.c_str());
- if (!fileXML.is_open())
- {
- LL_WARNS(LOG_INV) << "unable to save inventory to: " << filename << LL_ENDL;
- return false;
- }
+ try
+ {
+ llofstream fileXML(filename.c_str());
+ if (!fileXML.is_open())
+ {
+ LL_WARNS(LOG_INV) << "Failed to open file. Unable to save inventory to: " << filename << LL_ENDL;
+ return false;
+ }
- LLSD cache_ver;
- cache_ver["inv_cache_version"] = sCurrentInvCacheVersion;
+ LLSD cache_ver;
+ cache_ver["inv_cache_version"] = sCurrentInvCacheVersion;
- fileXML << LLSDOStreamer<LLSDNotationFormatter>(cache_ver) << std::endl;
+ if (fileXML.fail())
+ {
+ LL_WARNS(LOG_INV) << "Failed to write cache version to file. Unable to save inventory to: " << filename << LL_ENDL;
+ return false;
+ }
- S32 count = categories.size();
- S32 cat_count = 0;
- S32 i;
- for(i = 0; i < count; ++i)
- {
- LLViewerInventoryCategory* cat = categories[i];
- if(cat->getVersion() != LLViewerInventoryCategory::VERSION_UNKNOWN)
- {
- fileXML << LLSDOStreamer<LLSDNotationFormatter>(cat->exportLLSD()) << std::endl;
- cat_count++;
- }
- }
+ fileXML << LLSDOStreamer<LLSDNotationFormatter>(cache_ver) << std::endl;
- S32 it_count = items.size();
- for(i = 0; i < it_count; ++i)
- {
- fileXML << LLSDOStreamer<LLSDNotationFormatter>(items[i]->asLLSD()) << std::endl;
- }
+ S32 count = categories.size();
+ S32 cat_count = 0;
+ S32 i;
+ for (i = 0; i < count; ++i)
+ {
+ LLViewerInventoryCategory* cat = categories[i];
+ if (cat->getVersion() != LLViewerInventoryCategory::VERSION_UNKNOWN)
+ {
+ fileXML << LLSDOStreamer<LLSDNotationFormatter>(cat->exportLLSD()) << std::endl;
+ cat_count++;
+ }
- fileXML.close();
+ if (fileXML.fail())
+ {
+ LL_WARNS(LOG_INV) << "Failed to write a folder to file. Unable to save inventory to: " << filename << LL_ENDL;
+ return false;
+ }
+ }
- LL_INFOS(LOG_INV) << "Inventory saved: " << cat_count << " categories, " << it_count << " items." << LL_ENDL;
+ S32 it_count = items.size();
+ for (i = 0; i < it_count; ++i)
+ {
+ fileXML << LLSDOStreamer<LLSDNotationFormatter>(items[i]->asLLSD()) << std::endl;
- return true;
+ if (fileXML.fail())
+ {
+ LL_WARNS(LOG_INV) << "Failed to write an item to file. Unable to save inventory to: " << filename << LL_ENDL;
+ return false;
+ }
+ }
+
+ fileXML.close();
+
+ LL_INFOS(LOG_INV) << "Inventory saved: " << cat_count << " categories, " << it_count << " items." << LL_ENDL;
+ }
+ catch (...)
+ {
+ LOG_UNHANDLED_EXCEPTION("");
+ LL_INFOS(LOG_INV) << "Failed to save inventory to: (" << filename << ")" << LL_ENDL;
+ return false;
+ }
+
+ return true;
}
// message handling functionality
@@ -3850,20 +3898,23 @@ void LLInventoryModel::dumpInventory() const
LLPointer<LLInventoryValidationInfo> LLInventoryModel::validate() const
{
LLPointer<LLInventoryValidationInfo> validation_info = new LLInventoryValidationInfo;
- S32 fatalities = 0;
+ S32 fatal_errs = 0;
S32 warnings = 0;
+ S32 loops = 0;
+ S32 orphaned = 0;
if (getRootFolderID().isNull())
{
LL_WARNS("Inventory") << "Fatal inventory corruption: no root folder id" << LL_ENDL;
validation_info->mFatalNoRootFolder = true;
- fatalities++;
+ fatal_errs++;
}
if (getLibraryRootFolderID().isNull())
{
+ // Probably shouldn't be a fatality, inventory can function without a library
LL_WARNS("Inventory") << "Fatal inventory corruption: no library root folder id" << LL_ENDL;
validation_info->mFatalNoLibraryRootFolder = true;
- fatalities++;
+ fatal_errs++;
}
if (mCategoryMap.size() + 1 != mParentChildCategoryTree.size())
@@ -3895,7 +3946,23 @@ LLPointer<LLInventoryValidationInfo> LLInventoryModel::validate() const
}
LLUUID topmost_ancestor_id;
// Will leave as null uuid on failure
- getObjectTopmostAncestor(cat_id, topmost_ancestor_id);
+ EAnscestorResult res = getObjectTopmostAncestor(cat_id, topmost_ancestor_id);
+ switch (res)
+ {
+ case ANSCESTOR_MISSING:
+ orphaned++;
+ break;
+ case ANSCESTOR_LOOP:
+ loops++;
+ break;
+ case ANSCESTOR_OK:
+ break;
+ default:
+ LL_WARNS("Inventory") << "Unknown ancestor error for " << cat_id << LL_ENDL;
+ warnings++;
+ break;
+ }
+
if (cat_id != cat->getUUID())
{
LL_WARNS("Inventory") << "cat id/index mismatch " << cat_id << " " << cat->getUUID() << LL_ENDL;
@@ -3995,8 +4062,8 @@ LLPointer<LLInventoryValidationInfo> LLInventoryModel::validate() const
// Topmost ancestor should be root or library.
LLUUID topmost_ancestor_id;
- bool found = getObjectTopmostAncestor(item_id, topmost_ancestor_id);
- if (!found)
+ EAnscestorResult found = getObjectTopmostAncestor(item_id, topmost_ancestor_id);
+ if (found != ANSCESTOR_OK)
{
LL_WARNS("Inventory") << "unable to find topmost ancestor for " << item_id << LL_ENDL;
warnings++;
@@ -4026,7 +4093,7 @@ LLPointer<LLInventoryValidationInfo> LLInventoryModel::validate() const
{
LL_WARNS("Inventory") << "cat " << cat_id << " name [" << cat->getName()
<< "] orphaned - no child cat array for alleged parent " << parent_id << LL_ENDL;
- warnings++;
+ orphaned++;
}
else
{
@@ -4044,6 +4111,7 @@ LLPointer<LLInventoryValidationInfo> LLInventoryModel::validate() const
{
LL_WARNS("Inventory") << "cat " << cat_id << " name [" << cat->getName()
<< "] orphaned - not found in child cat array of alleged parent " << parent_id << LL_ENDL;
+ orphaned++;
}
}
}
@@ -4052,7 +4120,7 @@ LLPointer<LLInventoryValidationInfo> LLInventoryModel::validate() const
LLFolderType::EType folder_type = cat->getPreferredType();
bool cat_is_in_library = false;
LLUUID topmost_id;
- if (getObjectTopmostAncestor(cat->getUUID(),topmost_id) && topmost_id == getLibraryRootFolderID())
+ if (getObjectTopmostAncestor(cat->getUUID(),topmost_id) == ANSCESTOR_OK && topmost_id == getLibraryRootFolderID())
{
cat_is_in_library = true;
}
@@ -4092,6 +4160,7 @@ LLPointer<LLInventoryValidationInfo> LLInventoryModel::validate() const
if (parent_id.isNull())
{
LL_WARNS("Inventory") << "item " << item_id << " name [" << item->getName() << "] has null parent id!" << LL_ENDL;
+ orphaned++;
}
else
{
@@ -4102,6 +4171,7 @@ LLPointer<LLInventoryValidationInfo> LLInventoryModel::validate() const
{
LL_WARNS("Inventory") << "item " << item_id << " name [" << item->getName()
<< "] orphaned - alleged parent has no child items list " << parent_id << LL_ENDL;
+ orphaned++;
}
else
{
@@ -4118,6 +4188,7 @@ LLPointer<LLInventoryValidationInfo> LLInventoryModel::validate() const
{
LL_WARNS("Inventory") << "item " << item_id << " name [" << item->getName()
<< "] orphaned - not found as child of alleged parent " << parent_id << LL_ENDL;
+ orphaned++;
}
}
@@ -4135,15 +4206,18 @@ LLPointer<LLInventoryValidationInfo> LLInventoryModel::validate() const
LL_WARNS("Inventory") << "link " << item->getUUID() << " type " << item->getActualType()
<< " missing backlink info at target_id " << target_id
<< LL_ENDL;
+ orphaned++;
}
// Links should have referents.
if (item->getActualType() == LLAssetType::AT_LINK && !target_item)
{
LL_WARNS("Inventory") << "broken item link " << item->getName() << " id " << item->getUUID() << LL_ENDL;
+ orphaned++;
}
else if (item->getActualType() == LLAssetType::AT_LINK_FOLDER && !target_cat)
{
LL_WARNS("Inventory") << "broken folder link " << item->getName() << " id " << item->getUUID() << LL_ENDL;
+ orphaned++;
}
if (target_item && target_item->getIsLinkType())
{
@@ -4215,8 +4289,8 @@ LLPointer<LLInventoryValidationInfo> LLInventoryModel::validate() const
if (is_automatic)
{
LL_WARNS("Inventory") << "Fatal inventory corruption: cannot create system folder of type " << ft << LL_ENDL;
- fatalities++;
- validation_info->mMissingRequiredSystemFolders.insert(LLFolderType::EType(ft));
+ fatal_errs++;
+ validation_info->mMissingRequiredSystemFolders.insert(folder_type);
}
else
{
@@ -4227,8 +4301,20 @@ LLPointer<LLInventoryValidationInfo> LLInventoryModel::validate() const
else if (count_under_root > 1)
{
LL_WARNS("Inventory") << "Fatal inventory corruption: system folder type has excess copies under root, type " << ft << " count " << count_under_root << LL_ENDL;
- validation_info->mDuplicateRequiredSystemFolders.insert(LLFolderType::EType(ft));
- fatalities++;
+ validation_info->mDuplicateRequiredSystemFolders.insert(folder_type);
+ if (!is_automatic && folder_type != LLFolderType::FT_SETTINGS)
+ {
+ // It is a fatal problem or can lead to fatal problems for COF,
+ // outfits, trash and other non-automatic folders.
+ fatal_errs++;
+ }
+ else
+ {
+ // For automatic folders it's not a fatal issue and shouldn't
+ // break inventory or other functionality further
+ // Exception: FT_SETTINGS is not automatic, but only deserves a warning.
+ warnings++;
+ }
}
if (count_elsewhere > 0)
{
@@ -4254,11 +4340,13 @@ LLPointer<LLInventoryValidationInfo> LLInventoryModel::validate() const
}
// FIXME need to fail login and tell user to retry, contact support if problem persists.
- bool valid = (fatalities == 0);
- LL_INFOS("Inventory") << "Validate done, fatal errors: " << fatalities << ", warnings: " << warnings << ", valid: " << valid << LL_ENDL;
+ bool valid = (fatal_errs == 0);
+ LL_INFOS("Inventory") << "Validate done, fatal errors: " << fatal_errs << ", warnings: " << warnings << ", valid: " << valid << LL_ENDL;
- validation_info->mFatalErrorCount = fatalities;
+ validation_info->mFatalErrorCount = fatal_errs;
validation_info->mWarningCount = warnings;
+ validation_info->mLoopCount = loops;
+ validation_info->mOrphanedCount = orphaned;
return validation_info;
}