diff options
author | Andrey Kleshchev <andreykproductengine@lindenlab.com> | 2022-08-17 18:06:51 +0300 |
---|---|---|
committer | Andrey Kleshchev <andreykproductengine@lindenlab.com> | 2022-08-17 20:32:12 +0300 |
commit | 5759be7cdf0f8fe0745265b85bab8c37bd2335be (patch) | |
tree | 374832dbe8e1401aa3a07bd76cf278354015b373 /indra | |
parent | 8e8c68720b936a3bd7e907639a966918d48e57bc (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')
-rw-r--r-- | indra/newview/llinventorymodel.cpp | 3 | ||||
-rw-r--r-- | indra/newview/llmarketplacefunctions.cpp | 126 | ||||
-rw-r--r-- | indra/newview/llmarketplacefunctions.h | 1 |
3 files changed, 87 insertions, 43 deletions
diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index 37500176ea..ace4de928e 100644 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -1838,7 +1838,8 @@ void LLInventoryModel::addChangedMask(U32 mask, const LLUUID& referent) } // Fix me: From DD-81, probably shouldn't be here, instead - // should be somewhere in an observer + // should be somewhere in an observer or in + // LLMarketplaceInventoryObserver::onIdleProcessQueue update_marketplace_category(referent, false); if (mask & LLInventoryObserver::ADD) 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 diff --git a/indra/newview/llmarketplacefunctions.h b/indra/newview/llmarketplacefunctions.h index fee9225f77..ec5de88189 100644 --- a/indra/newview/llmarketplacefunctions.h +++ b/indra/newview/llmarketplacefunctions.h @@ -240,6 +240,7 @@ public: void setUpdating(const LLUUID& folder_id, bool isUpdating); // Used to decide when to run a validation on listing folders + bool hasValidationWaiting() { return mValidationWaitingList.size() > 0; } void setValidationWaiting(const LLUUID& folder_id, S32 count); void decrementValidationWaiting(const LLUUID& folder_id, S32 count = 1); |