Skip to content

Commit 55931a2

Browse files
committed
Some cleanup changes
1 parent 07665b7 commit 55931a2

File tree

6 files changed

+149
-61
lines changed

6 files changed

+149
-61
lines changed

indra/llinventory/llfoldertype.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,24 @@ bool LLFolderType::lookupIsEnsembleType(EType folder_type)
195195
folder_type <= FT_ENSEMBLE_END);
196196
}
197197

198+
// static
199+
bool LLFolderType::lookupIsEssentialType(EType folder_type)
200+
{
201+
if (folder_type == FT_NONE)
202+
{
203+
return false;
204+
}
205+
206+
if (folder_type == FT_ROOT_INVENTORY)
207+
{
208+
return true;
209+
}
210+
211+
// Essential folders are those needed for basic viewer operation:
212+
// singleton system folders and ensemble (outfit) folders
213+
return lookupIsSingletonType(folder_type) || lookupIsEnsembleType(folder_type);
214+
}
215+
198216
// static
199217
LLAssetType::EType LLFolderType::folderTypeToAssetType(LLFolderType::EType folder_type)
200218
{

indra/llinventory/llfoldertype.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,8 @@ class LL_COMMON_API LLFolderType
109109
static bool lookupIsAutomaticType(EType folder_type);
110110
static bool lookupIsSingletonType(EType folder_type);
111111
static bool lookupIsEnsembleType(EType folder_type);
112+
// Returns true if this folder type should be fully loaded during async inventory startup
113+
static bool lookupIsEssentialType(EType folder_type);
112114

113115
static LLAssetType::EType folderTypeToAssetType(LLFolderType::EType folder_type);
114116
static LLFolderType::EType assetTypeToFolderType(LLAssetType::EType asset_type);

indra/newview/app_settings/settings.xml

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3291,6 +3291,39 @@
32913291
<key>Value</key>
32923292
<real>0.05</real>
32933293
</map>
3294+
<key>AsyncInventoryCapsTimeout</key>
3295+
<map>
3296+
<key>Comment</key>
3297+
<string>Maximum seconds to wait for inventory capabilities during async skeleton loading.</string>
3298+
<key>Persist</key>
3299+
<integer>1</integer>
3300+
<key>Type</key>
3301+
<string>F32</string>
3302+
<key>Value</key>
3303+
<real>45.0</real>
3304+
</map>
3305+
<key>AsyncInventoryFetchTimeout</key>
3306+
<map>
3307+
<key>Comment</key>
3308+
<string>Maximum seconds for the entire async inventory skeleton fetch process.</string>
3309+
<key>Persist</key>
3310+
<integer>1</integer>
3311+
<key>Type</key>
3312+
<string>F32</string>
3313+
<key>Value</key>
3314+
<real>180.0</real>
3315+
</map>
3316+
<key>AsyncInventoryEssentialTimeout</key>
3317+
<map>
3318+
<key>Comment</key>
3319+
<string>Maximum seconds to wait for essential inventory folders during async loading.</string>
3320+
<key>Persist</key>
3321+
<integer>1</integer>
3322+
<key>Type</key>
3323+
<string>F32</string>
3324+
<key>Value</key>
3325+
<real>90.0</real>
3326+
</map>
32943327
<key>ForceLoginURL</key>
32953328
<map>
32963329
<key>Comment</key>

indra/newview/llinventorymodel.cpp

Lines changed: 61 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -127,26 +127,30 @@ bool LLCanCache::operator()(LLInventoryCategory* cat, LLInventoryItem* item)
127127
// HACK: downcast
128128
LLViewerInventoryCategory* c = (LLViewerInventoryCategory*)cat;
129129

130-
bool descendents_match = true;
130+
// Cache the category if it has a valid version number.
131+
// Categories with mismatched descendent counts are still cached so that
132+
// we preserve the folder structure. During async skeleton loading, these
133+
// categories will be marked for refresh (VERSION_UNKNOWN) if their counts
134+
// don't match, ensuring they get fetched from the server.
131135
if (c->getVersion() != LLViewerInventoryCategory::VERSION_UNKNOWN)
132136
{
133137
const S32 descendents_server = c->getDescendentCount();
134138
const S32 descendents_actual = c->getViewerDescendentCount();
135-
descendents_match = (descendents_server == descendents_actual);
136139

137-
if (!descendents_match)
140+
if (descendents_server != descendents_actual)
138141
{
139142
LL_DEBUGS("AsyncInventory") << "Caching category with mismatched descendents"
140143
<< " cat_id=" << c->getUUID()
141144
<< " name=\"" << c->getName() << "\""
142145
<< " server_descendents=" << descendents_server
143146
<< " viewer_descendents=" << descendents_actual
147+
<< " (will be marked for refresh on next login)"
144148
<< LL_ENDL;
145149
}
146-
}
147150

148-
mCachedCatIDs.insert(c->getUUID());
149-
rv = true;
151+
mCachedCatIDs.insert(c->getUUID());
152+
rv = true;
153+
}
150154
}
151155
return rv;
152156
}
@@ -2192,6 +2196,20 @@ void LLInventoryModel::idleNotifyObservers()
21922196
// *FIX: Think I want this conditional or moved elsewhere...
21932197
handleResponses(true);
21942198

2199+
// Check if we have a pending notification from async inventory throttling
2200+
if (mAllowAsyncInventoryUpdates && mAsyncNotifyPending)
2201+
{
2202+
if (mAsyncNotifyTimer.getElapsedTimeF32() >= mAsyncNotifyIntervalSec)
2203+
{
2204+
// Timer has expired, force notification
2205+
mAsyncNotifyPending = false;
2206+
if (mModifyMask != LLInventoryObserver::NONE || (mChangedItemIDs.size() != 0))
2207+
{
2208+
notifyObservers();
2209+
}
2210+
}
2211+
}
2212+
21952213
if (mLinksRebuildList.size() > 0)
21962214
{
21972215
if (mModifyMask != LLInventoryObserver::NONE || (mChangedItemIDs.size() != 0))
@@ -2229,6 +2247,8 @@ void LLInventoryModel::notifyObservers()
22292247
{
22302248
if (mAsyncNotifyTimer.getElapsedTimeF32() < mAsyncNotifyIntervalSec)
22312249
{
2250+
// Mark that we have a pending notification that will be delivered
2251+
// on the next idleNotifyObservers() call after the timer expires
22322252
mAsyncNotifyPending = true;
22332253
return;
22342254
}
@@ -2424,6 +2444,13 @@ void LLInventoryModel::cache(
24242444
INCLUDE_TRASH,
24252445
can_cache);
24262446

2447+
// Fallback pass: catch any categories/items that collectDescendentsIf missed.
2448+
// This can happen when:
2449+
// 1. Categories have VERSION_UNKNOWN (e.g., during async loading)
2450+
// 2. Parent-child tree has broken links (orphaned folders)
2451+
// 3. Categories with mismatched descendent counts weren't added to mCachedCatIDs
2452+
// Without this pass, we'd lose 80k+ folders in deeply nested inventories.
2453+
// (I feel like this might be surfacing a bug somewhere...)
24272454
std::set<LLUUID> cached_category_ids;
24282455
std::set<LLUUID> cached_item_ids;
24292456
for (auto& cat_ptr : categories)
@@ -2441,8 +2468,6 @@ void LLInventoryModel::cache(
24412468
}
24422469
}
24432470

2444-
// Fallback pass: ensure every known category/item under the root is persisted
2445-
// even if the parent/child map failed to enumerate it.
24462471
for (auto& entry : mCategoryMap)
24472472
{
24482473
LLViewerInventoryCategory* cat = entry.second;
@@ -2482,9 +2507,13 @@ void LLInventoryModel::cache(
24822507
{
24832508
continue;
24842509
}
2485-
items.push_back(item);
2486-
cached_item_ids.insert(item_id);
2510+
if (can_cache(NULL, item))
2511+
{
2512+
items.push_back(item);
2513+
cached_item_ids.insert(item_id);
2514+
}
24872515
}
2516+
24882517
// Use temporary file to avoid potential conflicts with other
24892518
// instances (even a 'read only' instance unzips into a file)
24902519
std::string temp_file = gDirUtilp->getTempFilename();
@@ -3269,19 +3298,26 @@ void LLInventoryModel::buildParentChildMap(bool run_validation)
32693298
{
32703299
LL_INFOS(LOG_INV) << "LLInventoryModel::buildParentChildMap()" << LL_ENDL;
32713300

3272-
// Rebuild from scratch so we do not accumulate duplicate children
3273-
// across consecutive calls triggered during async skeleton hydration.
3274-
std::for_each(
3275-
mParentChildCategoryTree.begin(),
3276-
mParentChildCategoryTree.end(),
3277-
DeletePairedPointer());
3278-
mParentChildCategoryTree.clear();
3301+
// Clear existing parent-child maps if they exist to avoid duplicate entries.
3302+
// This handles the case where buildParentChildMap is called multiple times
3303+
// during async skeleton loading (once without validation, once with).
3304+
if (!mParentChildCategoryTree.empty())
3305+
{
3306+
std::for_each(
3307+
mParentChildCategoryTree.begin(),
3308+
mParentChildCategoryTree.end(),
3309+
DeletePairedPointer());
3310+
mParentChildCategoryTree.clear();
3311+
}
32793312

3280-
std::for_each(
3281-
mParentChildItemTree.begin(),
3282-
mParentChildItemTree.end(),
3283-
DeletePairedPointer());
3284-
mParentChildItemTree.clear();
3313+
if (!mParentChildItemTree.empty())
3314+
{
3315+
std::for_each(
3316+
mParentChildItemTree.begin(),
3317+
mParentChildItemTree.end(),
3318+
DeletePairedPointer());
3319+
mParentChildItemTree.clear();
3320+
}
32853321

32863322
mCategoryLock.clear();
32873323
mItemLock.clear();
@@ -3332,7 +3368,6 @@ void LLInventoryModel::buildParentChildMap(bool run_validation)
33323368
S32 i;
33333369
S32 lost = 0;
33343370
cat_array_t lost_cats;
3335-
size_t tree_links_inserted = 0;
33363371
for (auto& cat : cats)
33373372
{
33383373
catsp = getUnlockedCatArray(cat->getParentUUID());
@@ -3343,7 +3378,6 @@ void LLInventoryModel::buildParentChildMap(bool run_validation)
33433378
cat->getPreferredType() == LLFolderType::FT_ROOT_INVENTORY ))
33443379
{
33453380
catsp->push_back(cat);
3346-
++tree_links_inserted;
33473381
}
33483382
else
33493383
{
@@ -3398,7 +3432,6 @@ void LLInventoryModel::buildParentChildMap(bool run_validation)
33983432
if(catsp)
33993433
{
34003434
catsp->push_back(cat);
3401-
++tree_links_inserted;
34023435
}
34033436
else
34043437
{
@@ -3414,7 +3447,6 @@ void LLInventoryModel::buildParentChildMap(bool run_validation)
34143447
// have to do is iterate over the items and put them in the right
34153448
// place.
34163449
item_array_t items;
3417-
size_t item_links_inserted = 0;
34183450
if(!mItemMap.empty())
34193451
{
34203452
LLPointer<LLViewerInventoryItem> item;
@@ -3432,7 +3464,6 @@ void LLInventoryModel::buildParentChildMap(bool run_validation)
34323464
if(itemsp)
34333465
{
34343466
itemsp->push_back(item);
3435-
++item_links_inserted;
34363467
}
34373468
else
34383469
{
@@ -3450,7 +3481,6 @@ void LLInventoryModel::buildParentChildMap(bool run_validation)
34503481
if(itemsp)
34513482
{
34523483
itemsp->push_back(item);
3453-
++item_links_inserted;
34543484
}
34553485
else
34563486
{
@@ -3491,19 +3521,13 @@ void LLInventoryModel::buildParentChildMap(bool run_validation)
34913521
}
34923522
}
34933523

3494-
const size_t category_tree_nodes = mParentChildCategoryTree.size();
3495-
const size_t item_tree_nodes = mParentChildItemTree.size();
3496-
const S32 lost_items = lost;
3497-
34983524
LL_INFOS("AsyncInventory") << "ParentChildMap summary"
34993525
<< " category_map_size=" << mCategoryMap.size()
3500-
<< " category_tree_nodes=" << category_tree_nodes
3501-
<< " category_links=" << tree_links_inserted
3526+
<< " category_tree_nodes=" << mParentChildCategoryTree.size()
35023527
<< " item_map_size=" << mItemMap.size()
3503-
<< " item_tree_nodes=" << item_tree_nodes
3504-
<< " item_links=" << item_links_inserted
3528+
<< " item_tree_nodes=" << mParentChildItemTree.size()
35053529
<< " lost_categories=" << lost_categories
3506-
<< " lost_items=" << lost_items
3530+
<< " lost_items=" << lost
35073531
<< LL_ENDL;
35083532

35093533
if (run_validation)

indra/newview/llinventorymodel.h

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -224,10 +224,18 @@ class LLInventoryModel
224224
// category pointers here, because broken links are also supported.
225225
typedef std::multimap<LLUUID, LLUUID> backlink_mmap_t;
226226
backlink_mmap_t mBacklinkMMap; // key = target_id: ID of item, values = link_ids: IDs of item or folder links referencing it.
227-
bool mAllowAsyncInventoryUpdates{false};
228-
bool mAsyncNotifyPending{false};
229-
LLFrameTimer mAsyncNotifyTimer;
230-
F32 mAsyncNotifyIntervalSec{0.05f};
227+
228+
// Async inventory loading support
229+
bool mAllowAsyncInventoryUpdates{false}; // True when async skeleton loading is active
230+
bool mAsyncNotifyPending{false}; // True when observer notification is throttled
231+
LLFrameTimer mAsyncNotifyTimer; // Timer for throttling observer notifications
232+
F32 mAsyncNotifyIntervalSec{0.05f}; // Minimum interval between notifications (seconds)
233+
234+
// Tracks category version numbers as they were when loaded from disk cache.
235+
// Used during async skeleton loading to determine if a cached category is still
236+
// up-to-date compared to the server version received via AIS.
237+
// Key: category UUID, Value: version number from cache
238+
// Cleared when async loading completes or when categories are deleted.
231239
std::map<LLUUID, S32> mCachedCategoryVersions;
232240
// For internal use only
233241
bool hasBacklinkInfo(const LLUUID& link_id, const LLUUID& target_id) const;

indra/newview/llstartup.cpp

Lines changed: 23 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -226,22 +226,6 @@
226226

227227
namespace
228228
{
229-
bool isEssentialFolderType(LLFolderType::EType folder_type)
230-
{
231-
if (folder_type == LLFolderType::FT_NONE)
232-
{
233-
return false;
234-
}
235-
236-
if (folder_type == LLFolderType::FT_ROOT_INVENTORY)
237-
{
238-
return true;
239-
}
240-
241-
return LLFolderType::lookupIsSingletonType(folder_type)
242-
|| LLFolderType::lookupIsEnsembleType(folder_type);
243-
}
244-
245229
class LLAsyncInventorySkeletonLoader
246230
{
247231
public:
@@ -312,9 +296,9 @@ class LLAsyncInventorySkeletonLoader
312296
LLFrameTimer mTotalTimer;
313297
LLFrameTimer mEssentialTimer;
314298

315-
F32 mCapsTimeoutSec = 45.f;
316-
F32 mFetchTimeoutSec = 180.f;
317-
F32 mEssentialTimeoutSec = 90.f;
299+
F32 mCapsTimeoutSec;
300+
F32 mFetchTimeoutSec;
301+
F32 mEssentialTimeoutSec;
318302

319303
boost::signals2::connection mCapsConnection;
320304
bool mIdleRegistered = false;
@@ -341,6 +325,12 @@ void LLAsyncInventorySkeletonLoader::reset()
341325

342326
const U32 requested = gSavedSettings.getU32("AsyncInventoryMaxConcurrentFetches");
343327
mMaxConcurrentFetches = std::clamp(requested, 1U, 8U);
328+
329+
// Load timeout settings
330+
mCapsTimeoutSec = gSavedSettings.getF32("AsyncInventoryCapsTimeout");
331+
mFetchTimeoutSec = gSavedSettings.getF32("AsyncInventoryFetchTimeout");
332+
mEssentialTimeoutSec = gSavedSettings.getF32("AsyncInventoryEssentialTimeout");
333+
344334
mSawCurrentOutfitFolder = false;
345335
}
346336

@@ -628,7 +618,7 @@ void LLAsyncInventorySkeletonLoader::evaluateChildren(const FetchRequest& reques
628618
{
629619
child_essential = true;
630620
}
631-
else if (isEssentialFolderType(child->getPreferredType()))
621+
else if (LLFolderType::lookupIsEssentialType(child->getPreferredType()))
632622
{
633623
child_essential = true;
634624
}
@@ -2673,6 +2663,19 @@ bool idle_startup()
26732663
LL_WARNS("AppInit") << "Async inventory skeleton failed: " << failure_reason << LL_ENDL;
26742664
login_instance->recordAsyncInventoryFailure();
26752665

2666+
// Invalidate the cache to prevent corrupt data from being loaded on next login
2667+
const LLUUID& agent_id = gAgent.getID();
2668+
if (agent_id.notNull())
2669+
{
2670+
std::string cache_filename = LLInventoryModel::getInvCacheAddres(agent_id);
2671+
cache_filename.append(".gz");
2672+
if (LLFile::isfile(cache_filename))
2673+
{
2674+
LL_WARNS("AppInit") << "Removing potentially corrupt inventory cache: " << cache_filename << LL_ENDL;
2675+
LLFile::remove(cache_filename);
2676+
}
2677+
}
2678+
26762679
LLSD args;
26772680
std::string localized_message = LLTrans::getString("AsyncInventorySkeletonFailure");
26782681
if (!failure_reason.empty())

0 commit comments

Comments
 (0)