Skip to content

Async inventory - cleaned up#5839

Open
marchcat wants to merge 5 commits into
release/26.3from
marchcat/async-inventory
Open

Async inventory - cleaned up#5839
marchcat wants to merge 5 commits into
release/26.3from
marchcat/async-inventory

Conversation

@marchcat
Copy link
Copy Markdown
Contributor

"Clean" version of #4893 - the same diff, but squashed into three commits.

}
else
{
mFetchQueue.push_back(request);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can understand essential folders, but why are we always fetching non-essential folders with minimal depth?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After the essential folders load, the rest are fetched gradually to build the full tree. Minimal initial depth keeps loading fast, while deeper folders load only when expanded.

Copy link
Copy Markdown
Contributor

@akleshchev akleshchev May 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

while deeper folders load only when expanded

That's not how it works. For filtering to work properly bulk fetch always gets started and will 'bulk' request inventory using high depth, doing more partial requests slows everything down and breaks things apart for the bulk fetch.

}
}

bool LLAsyncInventorySkeletonLoader::hasFetchedCurrentOutfit() const
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might be insufficient. "Current outfit" consists of links, we probably want to fetch those items first, otherwise some of the logic will fail due to 'broken' links.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It’s fine, but the flow is indirect: hasFetchedCurrentOutfit() only checks the COF folder, while linked folders are fetched separately through the essential queue before readiness is marked.

Copy link
Copy Markdown
Contributor

@akleshchev akleshchev May 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we have a cof specific request that fetches both cof and linked items in one go to avoid 'cloud' avatars where viewer has to slowly collect outfit by parts from different folders.

@akleshchev akleshchev requested a review from Copilot May 19, 2026 20:40
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR refactors and consolidates the async inventory skeleton loading work (from #4893) by integrating an AIS-driven background skeleton loader into the login/startup flow, improving inventory cache hydration/persistence, and reducing UI work during initial inventory panel construction.

Changes:

  • Adds LLAsyncInventorySkeletonLoader and wires it into LLStartUp to fetch inventory skeleton via AIS during/after login.
  • Extends LLInventoryModel to support cache-only skeleton hydration, cached category version tracking, async-update throttling, and an optimized parent/child map rebuild.
  • Optimizes inventory UI initialization by building only root + essential system folder descendants eagerly and deferring deeper view creation.

Reviewed changes

Copilot reviewed 14 out of 14 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
indra/newview/skins/default/xui/en/strings.xml Adds a localized login error string for async inventory skeleton failures.
indra/newview/llstartup.cpp Selects legacy vs async skeleton paths; starts/updates async loader; handles failure recovery and transitions.
indra/newview/lllogininstance.h Exposes async inventory support/force flags and success/failure recording APIs.
indra/newview/lllogininstance.cpp Adds suppression/force logic and requests async skeleton capability at login.
indra/newview/llinventorypanel.h Declares helper for building essential child views.
indra/newview/llinventorypanel.cpp Lazily builds inventory folder views; eagerly builds essential system folder children.
indra/newview/llinventorymodel.h Adds cache-only skeleton load, async-update throttling, cached version tracking, and validation toggle for parent/child map build.
indra/newview/llinventorymodel.cpp Implements cache-only hydration, throttled notifications, cached version tracking, optimized parent/child map rebuild, and cache persistence tweaks.
indra/newview/llasyncinventoryskeletonloader.h Introduces async skeleton loader interface and globals used during startup.
indra/newview/llasyncinventoryskeletonloader.cpp Implements the AIS-driven async skeleton fetch scheduler/state machine.
indra/newview/CMakeLists.txt Adds new async loader source/header to the build.
indra/newview/app_settings/settings.xml Adds debug/settings knobs for async inventory (force, concurrency, throttling, timeouts).
indra/llinventory/llfoldertype.h Adds lookupIsEssentialType() API.
indra/llinventory/llfoldertype.cpp Implements essential folder-type classification for async startup loading.
Comments suppressed due to low confidence (1)

indra/newview/llinventorymodel.cpp:3974

  • The item import logic has an inconsistent check/message: it logs "null item id" for AT_UNKNOWN type, and the nested if (inv_item->getType() == AT_UNKNOWN) inside the else branch is unreachable because item_type was already checked. This makes the cats_to_update path dead and likely changes cache invalidation behavior. Simplify to a single type check and update the log message to match the condition.
                    const LLUUID& item_uuid = inv_item->getUUID();
                    if (item_uuid.isNull())
                    {
                        LL_DEBUGS(LOG_INV) << "Ignoring inventory with null item id: "
                            << inv_item->getName() << LL_ENDL;
                    }
                    else
                    {
                        const LLAssetType::EType item_type = inv_item->getType();
                        if (item_type == LLAssetType::AT_UNKNOWN)
                        {
                            LL_DEBUGS(LOG_INV) << "Ignoring inventory with null item id: " << inv_item->getName() << LL_ENDL;
                        }
                        else
                        {
                            if (inv_item->getType() == LLAssetType::AT_UNKNOWN)
                            {
                                cats_to_update.insert(inv_item->getParentUUID());
                            }
                            else
                            {
                                items.push_back(inv_item);
                            }
                        }

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread indra/newview/llasyncinventoryskeletonloader.cpp
Comment thread indra/newview/llasyncinventoryskeletonloader.cpp
Comment thread indra/newview/llasyncinventoryskeletonloader.cpp
Comment thread indra/newview/app_settings/settings.xml Outdated
Comment thread indra/newview/llstartup.cpp
@akleshchev
Copy link
Copy Markdown
Contributor

akleshchev commented May 20, 2026

idle_startup : Using legacy inventory skeleton payload

What region can I test this at?

Also this, not sure if this is a problem, might be an aditi thing:

2026-05-20T16:09:30Z WARNING #Inventory# newview/llinventorymodel.cpp(940) LLInventoryModel::findCategoryUUIDForTypeInRoot : Tried to find folder, type 23 but category does not exist
2026-05-20T16:09:30Z WARNING #Inventory# newview/llinventorymodel.cpp(940) LLInventoryModel::findCategoryUUIDForTypeInRoot : Tried to find folder, type 14 but category does not exist
2026-05-20T16:09:30Z WARNING #Inventory# newview/llinventorymodel.cpp(940) LLInventoryModel::findCategoryUUIDForTypeInRoot : Tried to find folder, type 3 but category does not exist
2026-05-20T16:09:30Z WARNING #Inventory# newview/llinventorymodel.cpp(940) LLInventoryModel::findCategoryUUIDForTypeInRoot : Tried to find folder, type 14 but category does not exist

@akleshchev
Copy link
Copy Markdown
Contributor

I tried force enabling async inventory (supposed to work?) and got broken link spam, like this:
2026-05-20T16:49:47Z INFO #Inventory# newview/llinventorymodel.cpp(2682) LLInventoryModel::addItem : Adding broken link [ name: test itemID: 141d0017-9c5a-3792-aa38-072cc8cfd634 assetID: 3589a0d0-b17c-940d-5e1f-5e836f681ded ) parent: 7a49997e-cd49-4e4f-9be3-28b37cdd7c68

@marchcat
Copy link
Copy Markdown
Contributor Author

What region can I test this at?

Any region should work (the async path uses existing AIS API), just set ForceAsyncInventorySkeleton=1 in debug settings.

LLInventoryModel::findCategoryUUIDForTypeInRoot : Tried to find folder, type 23 but category does not exist

Those are FT_LANDMARK (3), FT_TRASH (14), and FT_FAVORITE (23). In force-async mode, createCommonSystemCategories() runs before AIS has finished fetching, so findCategoryUUIDForType can't find them yet. This should be harmless, they get discovered once the root fetch is completed.

I tried force enabling async inventory (supposed to work?) and got broken link spam

This is expected in force-async mode: items are loaded from cache but their link targets may not exist in the model yet (loaded in a different order or not yet fetched from AIS). Once the full skeleton loads, these links should resolve.
The spam is cosmetic, addItem() logs "broken link" but it doesn't discard them.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants