summaryrefslogtreecommitdiff
path: root/indra/newview/llinventorymodel.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'indra/newview/llinventorymodel.cpp')
-rw-r--r--indra/newview/llinventorymodel.cpp111
1 files changed, 101 insertions, 10 deletions
diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp
index baf34b42ff..c57e41e9b3 100644
--- a/indra/newview/llinventorymodel.cpp
+++ b/indra/newview/llinventorymodel.cpp
@@ -81,6 +81,10 @@ BOOL LLInventoryModel::sTimelyFetchPending = FALSE;
LLFrameTimer LLInventoryModel::sFetchTimer;
S16 LLInventoryModel::sBulkFetchCount = 0;
+// Increment this if the inventory contents change in a non-backwards-compatible way.
+// For viewer 2, the addition of link items makes a pre-viewer-2 cache incorrect.
+const S32 LLInventoryModel::sCurrentInvCacheVersion = 2;
+
// RN: for some reason, using std::queue in the header file confuses the compiler which things it's an xmlrpc_queue
static std::deque<LLUUID> sFetchQueue;
@@ -172,6 +176,7 @@ LLInventoryModel::LLInventoryModel()
mRootFolderID(),
mLibraryRootFolderID(),
mLibraryOwnerID(),
+ mIsNotifyObservers(FALSE),
mIsAgentInvUsable(false)
{
}
@@ -533,7 +538,10 @@ void LLInventoryModel::updateLinkedItems(const LLUUID& object_id)
item_array,
LLInventoryModel::INCLUDE_TRASH,
is_linked_item_match);
-
+ if (cat_array.empty() && item_array.empty())
+ {
+ return;
+ }
for (LLInventoryModel::cat_array_t::iterator cat_iter = cat_array.begin();
cat_iter != cat_array.end();
cat_iter++)
@@ -635,6 +643,7 @@ U32 LLInventoryModel::updateItem(const LLViewerInventoryItem* item)
new_item = old_item;
LLUUID old_parent_id = old_item->getParentUUID();
LLUUID new_parent_id = item->getParentUUID();
+
if(old_parent_id != new_parent_id)
{
// need to update the parent-child tree
@@ -1129,6 +1138,15 @@ BOOL LLInventoryModel::containsObserver(LLInventoryObserver* observer) const
// The optional argument 'service_name' is used by Agent Inventory Service [DEV-20328]
void LLInventoryModel::notifyObservers(const std::string service_name)
{
+ if (mIsNotifyObservers)
+ {
+ // Within notifyObservers, something called notifyObservers
+ // again. This type of recursion is unsafe because it causes items to be
+ // processed twice, and this can easily lead to infinite loops.
+ llwarns << "Call was made to notifyObservers within notifyObservers!" << llendl;
+ return;
+ }
+ mIsNotifyObservers = TRUE;
for (observer_list_t::iterator iter = mObservers.begin();
iter != mObservers.end(); )
{
@@ -1150,12 +1168,21 @@ void LLInventoryModel::notifyObservers(const std::string service_name)
mModifyMask = LLInventoryObserver::NONE;
mChangedItemIDs.clear();
+ mIsNotifyObservers = FALSE;
}
// store flag for change
// and id of object change applies to
void LLInventoryModel::addChangedMask(U32 mask, const LLUUID& referent)
{
+ if (mIsNotifyObservers)
+ {
+ // Something marked an item for change within a call to notifyObservers
+ // (which is in the process of processing the list of items marked for change).
+ // This means the change may fail to be processed.
+ llwarns << "Adding changed mask within notify observers! Change will likely be lost." << llendl;
+ }
+
mModifyMask |= mask;
if (referent.notNull())
{
@@ -1267,6 +1294,11 @@ void LLInventoryModel::fetchInventoryResponder::error(U32 status, const std::str
bool LLInventoryModel::fetchDescendentsOf(const LLUUID& folder_id)
{
+ if(folder_id.isNull())
+ {
+ llwarns << "Calling fetch descendents on NULL folder id!" << llendl;
+ return false;
+ }
LLViewerInventoryCategory* cat = getCategory(folder_id);
if(!cat)
{
@@ -1823,17 +1855,25 @@ void LLInventoryModel::addCategory(LLViewerInventoryCategory* category)
void LLInventoryModel::addItem(LLViewerInventoryItem* item)
{
//llinfos << "LLInventoryModel::addItem()" << llendl;
+
+ // This can happen if assettype enums from llassettype.h ever change.
+ // For example, there is a known backwards compatibility issue in some viewer prototypes prior to when
+ // the AT_LINK enum changed from 23 to 24.
+ if ((item->getType() == LLAssetType::AT_NONE)
+ || LLAssetType::lookup(item->getType()) == LLAssetType::badLookup())
+ {
+ llwarns << "Got bad asset type for item [ name: " << item->getName() << " type: " << item->getType() << " inv-type: " << item->getInventoryType() << " ], ignoring." << llendl;
+ return;
+ }
if(item)
{
// This condition means that we tried to add a link without the baseobj being in memory.
// The item will show up as a broken link.
if (item->getIsBrokenLink())
{
- llwarns << "Add link item without baseobj present ( name: " << item->getName() << " itemID: " << item->getUUID() << " assetID: " << item->getAssetUUID() << " ) parent: " << item->getParentUUID() << llendl;
-// llassert_always(FALSE); // DO NOT MERGE THIS IN. This is an AVP debugging line. If this line triggers, it means that you just loaded in a broken link. Unless that happens because you actually deleted a baseobj without deleting the link, it's indicative of a serious problem (likely with your inventory) and should be diagnosed.
+ llinfos << "Adding broken link [ name: " << item->getName() << " itemID: " << item->getUUID() << " assetID: " << item->getAssetUUID() << " ) parent: " << item->getParentUUID() << llendl;
}
mItemMap[item->getUUID()] = item;
- //mInventory[item->getUUID()] = item;
}
}
@@ -2101,7 +2141,8 @@ bool LLInventoryModel::loadSkeleton(
llinfos << "Unable to gunzip " << gzip_filename << llendl;
}
}
- if(loadFromFile(inventory_filename, categories, items))
+ bool is_cache_obsolete = false;
+ if(loadFromFile(inventory_filename, categories, items, is_cache_obsolete))
{
// We were able to find a cache of files. So, use what we
// found to generate a set of categories we should add. We
@@ -2158,7 +2199,7 @@ bool LLInventoryModel::loadSkeleton(
// Add all the items loaded which are parented to a
// category with a correctly cached parent
- count = items.count();
+ S32 bad_link_count = 0;
cat_map_t::iterator unparented = mCategoryMap.end();
for(item_array_t::const_iterator item_iter = items.begin();
item_iter != items.end();
@@ -2175,7 +2216,11 @@ bool LLInventoryModel::loadSkeleton(
// This can happen if the linked object's baseobj is removed from the cache but the linked object is still in the cache.
if (item->getIsBrokenLink())
{
- llinfos << "Attempted to cached link item without baseobj present ( itemID: " << item->getUUID() << " assetID: " << item->getAssetUUID() << " ) " << llendl;
+ bad_link_count++;
+ lldebugs << "Attempted to add cached link item without baseobj present ( name: "
+ << item->getName() << " itemID: " << item->getUUID()
+ << " assetID: " << item->getAssetUUID()
+ << " ). Ignoring and invalidating " << cat->getName() << " . " << llendl;
invalid_categories.insert(cit->second);
continue;
}
@@ -2185,6 +2230,12 @@ bool LLInventoryModel::loadSkeleton(
}
}
}
+ if (bad_link_count > 0)
+ {
+ llinfos << "Attempted to add " << bad_link_count
+ << " cached link items without baseobj present. "
+ << "The corresponding categories were invalidated." << llendl;
+ }
}
else
{
@@ -2236,6 +2287,12 @@ bool LLInventoryModel::loadSkeleton(
// clean up the gunzipped file.
LLFile::remove(inventory_filename);
}
+ if(is_cache_obsolete)
+ {
+ // If out of date, remove the gzipped file too.
+ llwarns << "Inv cache out of date, removing" << llendl;
+ LLFile::remove(gzip_filename);
+ }
categories.clear(); // will unref and delete entries
}
@@ -2634,7 +2691,8 @@ bool LLUUIDAndName::operator>(const LLUUIDAndName& rhs) const
// static
bool LLInventoryModel::loadFromFile(const std::string& filename,
LLInventoryModel::cat_array_t& categories,
- LLInventoryModel::item_array_t& items)
+ LLInventoryModel::item_array_t& items,
+ bool &is_cache_obsolete)
{
if(filename.empty())
{
@@ -2651,11 +2709,32 @@ bool LLInventoryModel::loadFromFile(const std::string& filename,
// *NOTE: This buffer size is hard coded into scanf() below.
char buffer[MAX_STRING]; /*Flawfinder: ignore*/
char keyword[MAX_STRING]; /*Flawfinder: ignore*/
+ char value[MAX_STRING]; /*Flawfinder: ignore*/
+ is_cache_obsolete = true; // Obsolete until proven current
while(!feof(file) && fgets(buffer, MAX_STRING, file))
{
- sscanf(buffer, " %254s", keyword); /* Flawfinder: ignore */
- if(0 == strcmp("inv_category", keyword))
+ sscanf(buffer, " %126s %126s", keyword, value); /* Flawfinder: ignore */
+ if(0 == strcmp("inv_cache_version", keyword))
+ {
+ S32 version;
+ int succ = sscanf(value,"%d",&version);
+ if ((1 == succ) && (version == sCurrentInvCacheVersion))
+ {
+ // Cache is up to date
+ is_cache_obsolete = false;
+ continue;
+ }
+ else
+ {
+ // Cache is out of date
+ break;
+ }
+ }
+ else if(0 == strcmp("inv_category", keyword))
{
+ if (is_cache_obsolete)
+ break;
+
LLPointer<LLViewerInventoryCategory> inv_cat = new LLViewerInventoryCategory(LLUUID::null);
if(inv_cat->importFileLocal(file))
{
@@ -2669,6 +2748,9 @@ bool LLInventoryModel::loadFromFile(const std::string& filename,
}
else if(0 == strcmp("inv_item", keyword))
{
+ if (is_cache_obsolete)
+ break;
+
LLPointer<LLViewerInventoryItem> inv_item = new LLViewerInventoryItem;
if( inv_item->importFileLocal(file) )
{
@@ -2700,6 +2782,8 @@ bool LLInventoryModel::loadFromFile(const std::string& filename,
}
}
fclose(file);
+ if (is_cache_obsolete)
+ return false;
return true;
}
@@ -2721,6 +2805,7 @@ bool LLInventoryModel::saveToFile(const std::string& filename,
return false;
}
+ fprintf(file, "\tinv_cache_version\t%d\n",sCurrentInvCacheVersion);
S32 count = categories.count();
S32 i;
for(i = 0; i < count; ++i)
@@ -3255,6 +3340,12 @@ void LLInventoryModel::processInventoryDescendents(LLMessageSystem* msg,void**)
for(i = 0; i < count; ++i)
{
titem->unpackMessage(msg, _PREHASH_ItemData, i);
+ // If the item has already been added (e.g. from link prefetch), then it doesn't need to be re-added.
+ if (gInventory.getItem(titem->getUUID()))
+ {
+ llinfos << "Skipping prefetched item [ Name: " << titem->getName() << " | Type: " << titem->getActualType() << " | ItemUUID: " << titem->getUUID() << " ] " << llendl;
+ continue;
+ }
gInventory.updateItem(titem);
}