diff options
| author | Brad Payne (Vir Linden) <vir@lindenlab.com> | 2013-12-03 11:49:29 -0500 | 
|---|---|---|
| committer | Brad Payne (Vir Linden) <vir@lindenlab.com> | 2013-12-03 11:49:29 -0500 | 
| commit | 940cde3938217daf348bd62f719cae262bad86b0 (patch) | |
| tree | fedf4a1f1a2c450d64a241b2bd8963adbd9033f4 | |
| parent | c0d780cb4473c02e885c67fbc1bc30e87536d1b8 (diff) | |
SH-4640 WIP
| -rwxr-xr-x | indra/newview/llinventorybridge.cpp | 13 | ||||
| -rwxr-xr-x | indra/newview/llinventorymodel.cpp | 174 | ||||
| -rwxr-xr-x | indra/newview/llinventorymodel.h | 13 | 
3 files changed, 162 insertions, 38 deletions
| diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index 1f942f5f4b..4bce25c8b5 100755 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -1730,16 +1730,9 @@ BOOL LLItemBridge::removeItem()  	{  		if (!item->getIsLinkType())  		{ -			LLInventoryModel::cat_array_t cat_array; -			LLInventoryModel::item_array_t item_array; -			LLLinkedItemIDMatches is_linked_item_match(mUUID); -			gInventory.collectDescendentsIf(gInventory.getRootFolderID(), -											cat_array, -											item_array, -											LLInventoryModel::INCLUDE_TRASH, -											is_linked_item_match); - -			const U32 num_links = cat_array.size() + item_array.size(); +			LLInventoryModel::item_array_t item_array =  +				gInventory.collectLinksTo(mUUID, gInventory.getRootFolderID()); +			const U32 num_links = item_array.size();  			if (num_links > 0)  			{  				// Warn if the user is will break any links when deleting this item. diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index 891d7c821c..2c63203773 100755 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -127,6 +127,7 @@ LLInventoryModel gInventory;  LLInventoryModel::LLInventoryModel()  :	mModifyMask(LLInventoryObserver::ALL),  	mChangedItemIDs(), +	mBacklinkMMap(),  	mCategoryMap(),  	mItemMap(),  	mCategoryLock(), @@ -686,26 +687,8 @@ void LLInventoryModel::addChangedMaskForLinks(const LLUUID& object_id, U32 mask)  	if (!obj || obj->getIsLinkType())  		return; -	LLInventoryModel::cat_array_t cat_array; -	LLInventoryModel::item_array_t item_array; -	LLLinkedItemIDMatches is_linked_item_match(object_id); -	collectDescendentsIf(gInventory.getRootFolderID(), -						 cat_array, -						 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++) -	{ -		LLViewerInventoryCategory *linked_cat = (*cat_iter); -		addChangedMask(mask, linked_cat->getUUID()); -	}; - +	LLInventoryModel::item_array_t item_array =  +		collectLinksTo(object_id,gInventory.getRootFolderID());  	for (LLInventoryModel::item_array_t::iterator iter = item_array.begin();  		 iter != item_array.end();  		 iter++) @@ -733,11 +716,14 @@ LLViewerInventoryItem* LLInventoryModel::getLinkedItem(const LLUUID& object_id)  	return object_id.notNull() ? getItem(getLinkedItemID(object_id)) : NULL;  } -LLInventoryModel::item_array_t LLInventoryModel::collectLinkedItems(const LLUUID& id, -																	const LLUUID& start_folder_id) +LLInventoryModel::item_array_t LLInventoryModel::collectLinksTo(const LLUUID& id, +																const LLUUID& start_folder_id)  { +	// Get item list via collectDescendents (slow!)  	item_array_t items;  	const LLInventoryObject *obj = getObject(id); +	// FIXME - should be as below, but this is causing a stack-smashing crash of cause TBD... check in the REBUILD code. +	//if (obj && obj->getIsLinkType())  	if (!obj || obj->getIsLinkType())  		return items; @@ -748,6 +734,38 @@ LLInventoryModel::item_array_t LLInventoryModel::collectLinkedItems(const LLUUID  						 items,  						 LLInventoryModel::INCLUDE_TRASH,  						 is_linked_item_match); + +	// Get via backlinks - fast. +	item_array_t fast_items; +	std::pair<backlink_mmap_t::iterator, backlink_mmap_t::iterator> range = mBacklinkMMap.equal_range(id); +	for (backlink_mmap_t::iterator it = range.first; it != range.second; ++it) +	{ +		LLViewerInventoryItem *item = getItem(it->second); +		if (item) +		{ +			fast_items.put(item); +		} +	} + +	// Validate equivalence. +	if (items.size() != fast_items.size()) +	{ +		llwarns << "size mismatch, " << items.size() << " != " << fast_items.size() << llendl; +	} +	for (item_array_t::iterator ita = items.begin(); ita != items.end(); ++ita) +	{ +		if (fast_items.find(*ita) == item_array_t::FAIL) +		{ +			llwarns << "in descendents search but not fast search " << (*ita)->getUUID() << llendl; +		} +	} +	for (item_array_t::iterator itb = fast_items.begin(); itb != fast_items.end(); ++itb) +	{ +		if (items.find(*itb) == item_array_t::FAIL) +		{ +			llwarns << "in fast search but not descendents search " << (*itb)->getUUID() << llendl; +		} +	}  	return items;  } @@ -1355,11 +1373,16 @@ void LLInventoryModel::deleteObject(const LLUUID& id, bool fix_broken_links, boo  		mParentChildCategoryTree.erase(id);  	}  	addChangedMask(LLInventoryObserver::REMOVE, id); -	 + +	bool is_link_type = obj->getIsLinkType(); +	if (is_link_type) +	{ +		removeBacklinkInfo(obj->getUUID(), obj->getLinkedUUID()); +	} +  	// Can't have links to links, so there's no need for this update  	// if the item removed is a link. Can also skip if source of the  	// update is getting broken link info separately. -	bool is_link_type = obj->getIsLinkType();  	obj = NULL; // delete obj  	if (fix_broken_links && !is_link_type)  	{ @@ -1373,7 +1396,7 @@ void LLInventoryModel::deleteObject(const LLUUID& id, bool fix_broken_links, boo  void LLInventoryModel::updateLinkedObjectsFromPurge(const LLUUID &baseobj_id)  { -	LLInventoryModel::item_array_t item_array = collectLinkedItems(baseobj_id); +	LLInventoryModel::item_array_t item_array = collectLinksTo(baseobj_id);  	// REBUILD is expensive, so clear the current change list first else  	// everything else on the changelist will also get rebuilt. @@ -1653,6 +1676,47 @@ void LLInventoryModel::addCategory(LLViewerInventoryCategory* category)  	}  } +bool LLInventoryModel::hasBacklinkInfo(const LLUUID& link_id, const LLUUID& target_id) const +{ +	std::pair <backlink_mmap_t::const_iterator, backlink_mmap_t::const_iterator> range; +	range = mBacklinkMMap.equal_range(target_id); +	for (backlink_mmap_t::const_iterator it = range.first; it != range.second; ++it) +	{ +		if (it->second == link_id) +		{ +			return true; +		} +	} +	return false; +} + +void LLInventoryModel::addBacklinkInfo(const LLUUID& link_id, const LLUUID& target_id) +{ +	if (!hasBacklinkInfo(link_id, target_id)) +	{ +		mBacklinkMMap.insert(std::make_pair(target_id, link_id)); +	} +} + +void LLInventoryModel::removeBacklinkInfo(const LLUUID& link_id, const LLUUID& target_id) +{ +	std::pair <backlink_mmap_t::iterator, backlink_mmap_t::iterator> range; +	range = mBacklinkMMap.equal_range(target_id); +	for (backlink_mmap_t::iterator it = range.first; it != range.second; ) +	{ +		if (it->second == link_id) +		{ +			backlink_mmap_t::iterator delete_it = it; // iterator will be invalidated by erase. +			++it; +			mBacklinkMMap.erase(delete_it); +		} +		else +		{ +			++it; +		} +	} +} +  void LLInventoryModel::addItem(LLViewerInventoryItem* item)  {  	llassert(item); @@ -1674,7 +1738,13 @@ void LLInventoryModel::addItem(LLViewerInventoryItem* item)  		{  			llinfos << "Adding broken link [ name: " << item->getName() << " itemID: " << item->getUUID() << " assetID: " << item->getAssetUUID() << " )  parent: " << item->getParentUUID() << llendl;  		} - +		if (item->getIsLinkType()) +		{ +			// Add back-link from linked-to UUID. +			const LLUUID& link_id = item->getUUID(); +			const LLUUID& target_id = item->getLinkedUUID(); +			addBacklinkInfo(link_id, target_id); +		}  		mItemMap[item->getUUID()] = item;  	}  } @@ -1693,6 +1763,7 @@ void LLInventoryModel::empty()  		mParentChildItemTree.end(),  		DeletePairedPointer());  	mParentChildItemTree.clear(); +	mBacklinkMMap.clear(); // forget all backlink information.  	mCategoryMap.clear(); // remove all references (should delete entries)  	mItemMap.clear(); // remove all references (should delete entries)  	mLastItem = NULL; @@ -3701,6 +3772,57 @@ bool LLInventoryModel::validate() const  			}  		} +		// Link checking +		if (item->getIsLinkType()) +		{ +			const LLUUID& link_id = item->getUUID(); +			const LLUUID& target_id = item->getLinkedUUID(); +			LLViewerInventoryItem *target_item = getItem(target_id); +			LLViewerInventoryCategory *target_cat = getCategory(target_id); +			// Linked-to UUID should have back reference to this link. +			if (!hasBacklinkInfo(link_id, target_id)) +			{ +				llwarns << "link " << item->getUUID() << " type " << item->getActualType() +						<< " missing backlink info at target_id " << target_id +						<< llendl; +			} +			// Links should have referents. +			if (item->getActualType() == LLAssetType::AT_LINK && !target_item) +			{ +				llwarns << "broken item link " << item->getName() << " id " << item->getUUID() << llendl; +			} +			else if (item->getActualType() == LLAssetType::AT_LINK_FOLDER && !target_cat) +			{ +				llwarns << "broken folder link " << item->getName() << " id " << item->getUUID() << llendl; +			} +			if (target_item && target_item->getIsLinkType()) +			{ +				llwarns << "link " << item->getName() << " references a link item " +						<< target_item->getName() << " " << target_item->getUUID() << llendl; +			} + +			// Links should not have backlinks. +			std::pair<backlink_mmap_t::const_iterator, backlink_mmap_t::const_iterator> range = mBacklinkMMap.equal_range(link_id); +			if (range.first != range.second) +			{ +				llwarns << "Link item " << item->getName() << " has backlinks!" << llendl; +			} +		} +		else +		{ +			// Check the backlinks of a non-link item. +			const LLUUID& target_id = item->getUUID(); +			std::pair<backlink_mmap_t::const_iterator, backlink_mmap_t::const_iterator> range = mBacklinkMMap.equal_range(target_id); +			for (backlink_mmap_t::const_iterator it = range.first; it != range.second; ++it) +			{ +				const LLUUID& link_id = it->second; +				LLViewerInventoryItem *link_item = getItem(link_id); +				if (!link_item || !link_item->getIsLinkType()) +				{ +					llwarns << "invalid backlink from target " << item->getName() << " to " << link_id << llendl; +				} +			} +		}  	}  	if (cat_lock > 0 || item_lock > 0) diff --git a/indra/newview/llinventorymodel.h b/indra/newview/llinventorymodel.h index 6b6d077a4b..0bb89bc5d4 100755 --- a/indra/newview/llinventorymodel.h +++ b/indra/newview/llinventorymodel.h @@ -154,6 +154,15 @@ private:  	parent_cat_map_t mParentChildCategoryTree;  	parent_item_map_t mParentChildItemTree; +	// Track links to items and categories. We do not store item or +	// category pointers here, because broken links are also supported. +	typedef std::multimap<LLUUID, LLUUID> backlink_mmap_t; +	backlink_mmap_t mBacklinkMMap; // key = target_id: ID of item, values = link_ids: IDs of item or folder links referencing it. +	// For internal use only +	bool hasBacklinkInfo(const LLUUID& link_id, const LLUUID& target_id) const; +	void addBacklinkInfo(const LLUUID& link_id, const LLUUID& target_id); +	void removeBacklinkInfo(const LLUUID& link_id, const LLUUID& target_id); +	  	//--------------------------------------------------------------------  	// Login  	//-------------------------------------------------------------------- @@ -217,8 +226,8 @@ public:  	// Collect all items in inventory that are linked to item_id.  	// Assumes item_id is itself not a linked item. -	item_array_t collectLinkedItems(const LLUUID& item_id, -									const LLUUID& start_folder_id = LLUUID::null); +	item_array_t collectLinksTo(const LLUUID& item_id, +								const LLUUID& start_folder_id = LLUUID::null);  	// Check if one object has a parent chain up to the category specified by UUID. | 
