summaryrefslogtreecommitdiff
path: root/indra/newview/llmarketplacefunctions.cpp
diff options
context:
space:
mode:
authorAndrey Kleshchev <andreykproductengine@lindenlab.com>2022-08-17 18:06:51 +0300
committerAndrey Kleshchev <andreykproductengine@lindenlab.com>2022-08-17 20:32:12 +0300
commit5759be7cdf0f8fe0745265b85bab8c37bd2335be (patch)
tree374832dbe8e1401aa3a07bd76cf278354015b373 /indra/newview/llmarketplacefunctions.cpp
parent8e8c68720b936a3bd7e907639a966918d48e57bc (diff)
SL-17834 MP window freezes when loading items from Inventory
1. Do not process all marketpalce changes at once, schedule them for later 2. Do not notifyObservers from notifyObservers
Diffstat (limited to 'indra/newview/llmarketplacefunctions.cpp')
-rw-r--r--indra/newview/llmarketplacefunctions.cpp126
1 files changed, 84 insertions, 42 deletions
diff --git a/indra/newview/llmarketplacefunctions.cpp b/indra/newview/llmarketplacefunctions.cpp
index 044c76ce2c..74616df079 100644
--- a/indra/newview/llmarketplacefunctions.cpp
+++ b/indra/newview/llmarketplacefunctions.cpp
@@ -30,6 +30,7 @@
#include "llagent.h"
#include "llbufferstream.h"
+#include "llcallbacklist.h"
#include "llinventoryfunctions.h"
#include "llinventoryobserver.h"
#include "llnotificationsutil.h"
@@ -605,20 +606,62 @@ public:
LLMarketplaceInventoryObserver() {}
virtual ~LLMarketplaceInventoryObserver() {}
virtual void changed(U32 mask);
+
+private:
+ static void onIdleProcessQueue(void *userdata);
+
+ // doesn't hold just marketplace related ids
+ static std::set<LLUUID> sAddQueue;
+ static std::set<LLUUID> sStructureQueue;
};
+std::set<LLUUID> LLMarketplaceInventoryObserver::sAddQueue;
+std::set<LLUUID> LLMarketplaceInventoryObserver::sStructureQueue;
+
void LLMarketplaceInventoryObserver::changed(U32 mask)
{
- // When things are added to the marketplace, we might need to re-validate and fix the containing listings
- if (mask & LLInventoryObserver::ADD)
+ bool idle_running = !sAddQueue.empty() && !sStructureQueue.empty();
+ bool needs_idle = false;
+ if (mask & LLInventoryObserver::ADD && LLMarketplaceData::instance().hasValidationWaiting())
{
+ // When things are added to the marketplace, we might need to re-validate and fix the containing listings
+ // just add whole list even if it contains items and non-marketplace folders
const std::set<LLUUID>& changed_items = gInventory.getChangedIDs();
-
- std::set<LLUUID>::const_iterator id_it = changed_items.begin();
- std::set<LLUUID>::const_iterator id_end = changed_items.end();
+ sAddQueue.insert(changed_items.begin(), changed_items.end());
+ needs_idle = true;
+ }
+
+ if (mask & (LLInventoryObserver::INTERNAL | LLInventoryObserver::STRUCTURE))
+ {
+ // When things are changed in the inventory, this can trigger a host of changes in the marketplace listings folder:
+ // * stock counts changing : no copy items coming in and out will change the stock count on folders
+ // * version and listing folders : moving those might invalidate the marketplace data itself
+ // Since we should cannot raise inventory change while the observer is called (the list will be cleared
+ // once observers are called) we need to raise a flag in the inventory to signal that things have been dirtied.
+ const std::set<LLUUID>& changed_items = gInventory.getChangedIDs();
+ sStructureQueue.insert(changed_items.begin(), changed_items.end());
+ needs_idle = true;
+ }
+
+ if (!idle_running && needs_idle)
+ {
+ gIdleCallbacks.addFunction(onIdleProcessQueue, NULL);
+ }
+}
+
+void LLMarketplaceInventoryObserver::onIdleProcessQueue(void *userdata)
+{
+ U64 start_time = LLTimer::getTotalTime(); // microseconds
+ const U64 MAX_PROCESSING_TIME = 1000;
+ U64 stop_time = start_time + MAX_PROCESSING_TIME;
+
+ if (!sAddQueue.empty())
+ {
+ std::set<LLUUID>::const_iterator id_it = sAddQueue.begin();
+ std::set<LLUUID>::const_iterator id_end = sAddQueue.end();
// First, count the number of items in this list...
S32 count = 0;
- for (;id_it != id_end; ++id_it)
+ for (; id_it != id_end; ++id_it)
{
LLInventoryObject* obj = gInventory.getObject(*id_it);
if (obj && (LLAssetType::AT_CATEGORY != obj->getType()))
@@ -629,56 +672,55 @@ void LLMarketplaceInventoryObserver::changed(U32 mask)
// Then, decrement the folders of that amount
// Note that of all of those, only one folder will be a listing folder (if at all).
// The other will be ignored by the decrement method.
- id_it = changed_items.begin();
- for (;id_it != id_end; ++id_it)
+ id_it = sAddQueue.begin();
+ for (; id_it != id_end; ++id_it)
{
LLInventoryObject* obj = gInventory.getObject(*id_it);
if (obj && (LLAssetType::AT_CATEGORY == obj->getType()))
{
- LLMarketplaceData::instance().decrementValidationWaiting(obj->getUUID(),count);
+ // can trigger notifyObservers
+ LLMarketplaceData::instance().decrementValidationWaiting(obj->getUUID(), count);
}
}
- }
-
- // When things are changed in the inventory, this can trigger a host of changes in the marketplace listings folder:
- // * stock counts changing : no copy items coming in and out will change the stock count on folders
- // * version and listing folders : moving those might invalidate the marketplace data itself
- // Since we should cannot raise inventory change while the observer is called (the list will be cleared
- // once observers are called) we need to raise a flag in the inventory to signal that things have been dirtied.
-
- if (mask & (LLInventoryObserver::INTERNAL | LLInventoryObserver::STRUCTURE))
- {
- const std::set<LLUUID>& changed_items = gInventory.getChangedIDs();
-
- std::set<LLUUID>::const_iterator id_it = changed_items.begin();
- std::set<LLUUID>::const_iterator id_end = changed_items.end();
- for (;id_it != id_end; ++id_it)
+ sAddQueue.clear();
+ }
+
+ std::set<LLUUID>::const_iterator id_it = sStructureQueue.begin();
+ while (id_it != sStructureQueue.end() && LLTimer::getTotalTime() < stop_time)
+ {
+ LLInventoryObject* obj = gInventory.getObject(*id_it);
+ if (obj)
{
- LLInventoryObject* obj = gInventory.getObject(*id_it);
- if (obj)
+ if (LLAssetType::AT_CATEGORY == obj->getType())
{
- if (LLAssetType::AT_CATEGORY == obj->getType())
+ // If it's a folder known to the marketplace, let's check it's in proper shape
+ if (LLMarketplaceData::instance().isListed(*id_it) || LLMarketplaceData::instance().isVersionFolder(*id_it))
{
- // If it's a folder known to the marketplace, let's check it's in proper shape
- if (LLMarketplaceData::instance().isListed(*id_it) || LLMarketplaceData::instance().isVersionFolder(*id_it))
- {
- LLInventoryCategory* cat = (LLInventoryCategory*)(obj);
- validate_marketplacelistings(cat);
- }
+ LLInventoryCategory* cat = (LLInventoryCategory*)(obj);
+ // can trigger notifyObservers
+ // can cause more structural changes
+ validate_marketplacelistings(cat);
}
- else
+ }
+ else
+ {
+ // If it's not a category, it's an item...
+ LLInventoryItem* item = (LLInventoryItem*)(obj);
+ // If it's a no copy item, we may need to update the label count of marketplace listings
+ if (!item->getPermissions().allowOperationBy(PERM_COPY, gAgent.getID(), gAgent.getGroupID()))
{
- // If it's not a category, it's an item...
- LLInventoryItem* item = (LLInventoryItem*)(obj);
- // If it's a no copy item, we may need to update the label count of marketplace listings
- if (!item->getPermissions().allowOperationBy(PERM_COPY, gAgent.getID(), gAgent.getGroupID()))
- {
- LLMarketplaceData::instance().setDirtyCount();
- }
+ LLMarketplaceData::instance().setDirtyCount();
}
}
}
- }
+ id_it = sStructureQueue.erase(id_it);
+ }
+
+ if (LLApp::isExiting() || sStructureQueue.empty())
+ {
+ // Nothing to do anymore
+ gIdleCallbacks.deleteFunction(onIdleProcessQueue, NULL);
+ }
}
// Tuple == Item