Skip to content

Commit aa0e913

Browse files
committed
#6014 Make inventory caching flat instead of recursive
1 parent 0b38f76 commit aa0e913

2 files changed

Lines changed: 96 additions & 56 deletions

File tree

indra/newview/llinventorymodel.cpp

Lines changed: 96 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828

2929
#include <typeinfo>
3030
#include <random>
31+
#include <thread>
3132

3233
#include "llinventorymodel.h"
3334

@@ -82,7 +83,7 @@ const S32 LLInventoryModel::sCurrentInvCacheVersion = 5;
8283
bool LLInventoryModel::sFirstTimeInViewer2 = true;
8384

8485
S32 LLInventoryModel::sPendingSystemFolders = 0;
85-
std::vector<std::thread> LLInventoryModel::sPendingCacheThreads;
86+
std::vector<std::thread> sPendingCacheThreads;
8687

8788
///----------------------------------------------------------------------------
8889
/// Local function declarations, constants, enums, and typedefs
@@ -101,45 +102,6 @@ struct InventoryIDPtrLess
101102
}
102103
};
103104

104-
class LLCanCache : public LLInventoryCollectFunctor
105-
{
106-
public:
107-
LLCanCache(LLInventoryModel* model) : mModel(model) {}
108-
virtual ~LLCanCache() {}
109-
virtual bool operator()(LLInventoryCategory* cat, LLInventoryItem* item);
110-
protected:
111-
LLInventoryModel* mModel;
112-
std::set<LLUUID> mCachedCatIDs;
113-
};
114-
115-
bool LLCanCache::operator()(LLInventoryCategory* cat, LLInventoryItem* item)
116-
{
117-
bool rv = false;
118-
if(item)
119-
{
120-
if(mCachedCatIDs.find(item->getParentUUID()) != mCachedCatIDs.end())
121-
{
122-
rv = true;
123-
}
124-
}
125-
else if(cat)
126-
{
127-
// HACK: downcast
128-
LLViewerInventoryCategory* c = (LLViewerInventoryCategory*)cat;
129-
if(c->getVersion() != LLViewerInventoryCategory::VERSION_UNKNOWN)
130-
{
131-
S32 descendents_server = c->getDescendentCount();
132-
S32 descendents_actual = c->getViewerDescendentCount();
133-
if(descendents_server == descendents_actual)
134-
{
135-
mCachedCatIDs.insert(c->getUUID());
136-
rv = true;
137-
}
138-
}
139-
}
140-
return rv;
141-
}
142-
143105
struct InventoryCallbackInfo
144106
{
145107
InventoryCallbackInfo(U32 callback, const LLUUID& inv_id) :
@@ -2372,20 +2334,98 @@ void LLInventoryModel::cache(
23722334
LL_PROFILE_ZONE_SCOPED;
23732335
LL_DEBUGS(LOG_INV) << "Caching " << parent_folder_id << " for " << agent_id
23742336
<< LL_ENDL;
2337+
23752338
LLViewerInventoryCategory* root_cat = getCategory(parent_folder_id);
2376-
if(!root_cat) return;
2339+
if (!root_cat)
2340+
{
2341+
LL_WARNS(LOG_INV) << "Root category not found for " << parent_folder_id << LL_ENDL;
2342+
return;
2343+
}
2344+
23772345
cat_array_t categories;
23782346
categories.push_back(root_cat);
23792347
item_array_t items;
23802348

2381-
LLCanCache can_cache(this);
2382-
can_cache(root_cat, NULL);
2383-
collectDescendentsIf(
2384-
parent_folder_id,
2385-
categories,
2386-
items,
2387-
INCLUDE_TRASH,
2388-
can_cache);
2349+
// Lambda to check if a category should be cached
2350+
// Only cache if it has known version and matching descendent counts
2351+
auto should_cache_category = [](LLViewerInventoryCategory* cat) -> bool {
2352+
if (!cat || cat->getVersion() == LLViewerInventoryCategory::VERSION_UNKNOWN)
2353+
{
2354+
return false;
2355+
}
2356+
S32 descendents_server = cat->getDescendentCount();
2357+
S32 descendents_actual = cat->getViewerDescendentCount();
2358+
return (descendents_server == descendents_actual);
2359+
};
2360+
2361+
// Track which folders we've verified as cacheable descendants
2362+
std::unordered_set<LLUUID> processed_folders;
2363+
processed_folders.insert(parent_folder_id);
2364+
2365+
// First pass: identify all cacheable descendant folders
2366+
// Use pair of (folder_id, should_save_children)
2367+
std::deque<std::pair<LLUUID, bool>> folders_to_check;
2368+
folders_to_check.push_back(std::make_pair(parent_folder_id, should_cache_category(root_cat)));
2369+
2370+
while (!folders_to_check.empty())
2371+
{
2372+
auto [current_id, save_children] = folders_to_check.front();
2373+
folders_to_check.pop_front();
2374+
2375+
if (save_children) // else incorrect count or version
2376+
{
2377+
auto item_it = mParentChildItemTree.find(current_id);
2378+
if (item_it != mParentChildItemTree.end() && item_it->second)
2379+
{
2380+
for (LLViewerInventoryItem* item : *(item_it->second))
2381+
{
2382+
if (item)
2383+
{
2384+
items.push_back(item);
2385+
}
2386+
}
2387+
}
2388+
}
2389+
2390+
// Get child categories directly from the parent-child tree
2391+
auto cat_it = mParentChildCategoryTree.find(current_id);
2392+
if (cat_it != mParentChildCategoryTree.end() && cat_it->second)
2393+
{
2394+
for (LLViewerInventoryCategory* child_cat : *(cat_it->second))
2395+
{
2396+
if (!child_cat)
2397+
{
2398+
continue;
2399+
}
2400+
2401+
// Verify ownership matches (library vs agent inventory)
2402+
if (child_cat->getOwnerID() != root_cat->getOwnerID())
2403+
{
2404+
LL_WARNS(LOG_INV) << "Owner mismatch in category tree: expected "
2405+
<< root_cat->getOwnerID() << " got "
2406+
<< child_cat->getOwnerID() << " for category "
2407+
<< child_cat->getName() << LL_ENDL;
2408+
continue;
2409+
}
2410+
2411+
const LLUUID& child_id = child_cat->getUUID();
2412+
2413+
// Only process each folder once
2414+
if (processed_folders.insert(child_id).second)
2415+
{
2416+
if (should_cache_category(child_cat))
2417+
{
2418+
categories.push_back(child_cat);
2419+
folders_to_check.push_back(std::make_pair(child_id, true));
2420+
}
2421+
else
2422+
{
2423+
folders_to_check.push_back(std::make_pair(child_id, false));
2424+
}
2425+
}
2426+
}
2427+
}
2428+
}
23892429

23902430
if (categories.empty() && items.empty())
23912431
{
@@ -2405,7 +2445,12 @@ void LLInventoryModel::cache(
24052445
std::string gzip_filename = getInvCacheAddres(agent_id);
24062446
gzip_filename.append(".gz");
24072447

2408-
// Launch detached packing thread
2448+
if (sPendingCacheThreads.empty())
2449+
{
2450+
LL_INFOS(LOG_INV) << "Inventory cache compression started" << LL_ENDL;
2451+
}
2452+
2453+
// Launch background packing thread
24092454
// Main thread is the only one modifying sPendingCacheThreads
24102455
sPendingCacheThreads.emplace_back(
24112456
[temp_file, gzip_filename]() {
@@ -2449,9 +2494,7 @@ void LLInventoryModel::waitForPendingCacheWrites()
24492494
}
24502495
}
24512496

2452-
F32 wait_time = wait_timer.getElapsedTimeF32();
2453-
LL_INFOS(LOG_INV) << "Inventory cache compressions completed in "
2454-
<< wait_time << "s" << LL_ENDL;
2497+
LL_INFOS(LOG_INV) << "Inventory cache compression completed" << LL_ENDL;
24552498
}
24562499
}
24572500

indra/newview/llinventorymodel.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -199,9 +199,6 @@ class LLInventoryModel
199199
// Wait for any pending async cache operations to complete
200200
static void waitForPendingCacheWrites();
201201
private:
202-
// Async gzip compression tracking
203-
static std::vector<std::thread> sPendingCacheThreads;
204-
205202
// Information for tracking the actual inventory. We index this
206203
// information in a lot of different ways so we can access
207204
// the inventory using several different identifiers.

0 commit comments

Comments
 (0)