summaryrefslogtreecommitdiff
path: root/indra
diff options
context:
space:
mode:
Diffstat (limited to 'indra')
-rw-r--r--indra/newview/llaisapi.cpp158
-rw-r--r--indra/newview/llaisapi.h13
-rw-r--r--indra/newview/llappearancemgr.cpp13
-rw-r--r--indra/newview/llinventorymodelbackgroundfetch.cpp195
-rw-r--r--indra/newview/llinventorymodelbackgroundfetch.h6
5 files changed, 320 insertions, 65 deletions
diff --git a/indra/newview/llaisapi.cpp b/indra/newview/llaisapi.cpp
index 6d13a06c54..c17b246ef1 100644
--- a/indra/newview/llaisapi.cpp
+++ b/indra/newview/llaisapi.cpp
@@ -51,6 +51,10 @@ std::list<AISAPI::ais_query_item_t> AISAPI::sPostponedQuery;
const S32 MAX_SIMULTANEOUS_COROUTINES = 2048;
+// AIS3 allows '*' requests, but in reality those will be cut at some point
+// Specify own depth to be able to anticipate it and mark folders as incomplete
+const S32 MAX_FOLDER_DEPTH_REQUEST = 50;
+
//-------------------------------------------------------------------------
/*static*/
bool AISAPI::isAvailable()
@@ -458,11 +462,11 @@ void AISAPI::FetchCategoryChildren(const LLUUID &catId, ITEM_TYPE type, bool rec
{
// can specify depth=*, but server side is going to cap requests
// and reject everything 'over the top',.
- depth = 50;
+ depth = MAX_FOLDER_DEPTH_REQUEST;
}
else
{
- depth = llmin(depth, 50);
+ depth = llmin(depth, MAX_FOLDER_DEPTH_REQUEST);
}
url += "?depth=" + std::to_string(depth);
@@ -511,11 +515,11 @@ void AISAPI::FetchCategoryChildren(const std::string &identifier, bool recursive
{
// can specify depth=*, but server side is going to cap requests
// and reject everything 'over the top',.
- depth = 50;
+ depth = MAX_FOLDER_DEPTH_REQUEST;
}
else
{
- depth = llmin(depth, 50);
+ depth = llmin(depth, MAX_FOLDER_DEPTH_REQUEST);
}
url += "?depth=" + std::to_string(depth);
@@ -562,11 +566,11 @@ void AISAPI::FetchCategoryCategories(const LLUUID &catId, ITEM_TYPE type, bool r
{
// can specify depth=*, but server side is going to cap requests
// and reject everything 'over the top',.
- depth = 50;
+ depth = MAX_FOLDER_DEPTH_REQUEST;
}
else
{
- depth = llmin(depth, 50);
+ depth = llmin(depth, MAX_FOLDER_DEPTH_REQUEST);
}
url += "?depth=" + std::to_string(depth);
@@ -592,6 +596,83 @@ void AISAPI::FetchCategoryCategories(const LLUUID &catId, ITEM_TYPE type, bool r
EnqueueAISCommand("FetchCategoryCategories", proc);
}
+void AISAPI::FetchCategorySubset(const LLUUID& catId,
+ const uuid_vec_t specificChildren,
+ ITEM_TYPE type,
+ bool recursive,
+ completion_t callback,
+ S32 depth)
+{
+ std::string cap = (type == INVENTORY) ? getInvCap() : getLibCap();
+ if (cap.empty())
+ {
+ LL_WARNS("Inventory") << "Inventory cap not found!" << LL_ENDL;
+ if (callback)
+ {
+ callback(LLUUID::null);
+ }
+ return;
+ }
+ if (specificChildren.empty())
+ {
+ LL_WARNS("Inventory") << "Empty request!" << LL_ENDL;
+ if (callback)
+ {
+ callback(LLUUID::null);
+ }
+ return;
+ }
+ // category/any_folder_id/children?depth=*&children=child_id1,child_id2,child_id3
+ std::string url = cap + std::string("/category/") + catId.asString() + "/children";
+
+ if (recursive)
+ {
+ depth = MAX_FOLDER_DEPTH_REQUEST;
+ }
+ else
+ {
+ depth = llmin(depth, MAX_FOLDER_DEPTH_REQUEST);
+ }
+
+ uuid_vec_t::const_iterator iter = specificChildren.begin();
+ uuid_vec_t::const_iterator end = specificChildren.end();
+
+ url += "?depth=" + std::to_string(depth) + "&children=" + iter->asString();
+ iter++;
+
+ while (iter != end)
+ {
+ url += "," + iter->asString();
+ iter++;
+ }
+
+ const S32 MAX_URL_LENGH = 2000; // RFC documentation specifies a maximum length of 2048
+ if (url.length() > MAX_URL_LENGH)
+ {
+ LL_WARNS("Inventory") << "Request url is too long, url: " << url << LL_ENDL;
+ }
+
+ invokationFn_t getFn = boost::bind(
+ // Humans ignore next line. It is just a cast to specify which LLCoreHttpUtil::HttpCoroutineAdapter routine overload.
+ static_cast<LLSD(LLCoreHttpUtil::HttpCoroutineAdapter::*)(LLCore::HttpRequest::ptr_t, const std::string&, LLCore::HttpOptions::ptr_t, LLCore::HttpHeaders::ptr_t)>
+ //----
+ // _1 -> httpAdapter
+ // _2 -> httpRequest
+ // _3 -> url
+ // _4 -> body
+ // _5 -> httpOptions
+ // _6 -> httpHeaders
+ (&LLCoreHttpUtil::HttpCoroutineAdapter::getAndSuspend), _1, _2, _3, _5, _6);
+
+ // get doesn't use body, can pass additional data
+ LLSD body;
+ body["depth"] = depth;
+ LLCoprocedureManager::CoProcedure_t proc(boost::bind(&AISAPI::InvokeAISCommandCoro,
+ _1, getFn, url, catId, body, callback, FETCHCATEGORYSUBSET));
+
+ EnqueueAISCommand("FetchCategorySubset", proc);
+}
+
/*static*/
// Will get COF folder, links in it and items those links point to
void AISAPI::FetchCOF(completion_t callback)
@@ -710,7 +791,7 @@ void AISAPI::onIdle(void *userdata)
}
/*static*/
-void AISAPI::onUpdateReceived(const std::string& context, const LLSD& update, COMMAND_TYPE type, const LLSD& request_body)
+void AISAPI::onUpdateReceived(const LLSD& update, COMMAND_TYPE type, const LLSD& request_body)
{
LLTimer timer;
if ( (type == UPDATECATEGORY || type == UPDATEITEM)
@@ -718,18 +799,8 @@ void AISAPI::onUpdateReceived(const std::string& context, const LLSD& update, CO
{
dump_sequential_xml(gAgentAvatarp->getFullname() + "_ais_update", update);
}
- bool is_fetch = (type == FETCHITEM)
- || (type == FETCHCATEGORYCHILDREN)
- || (type == FETCHCATEGORYCATEGORIES)
- || (type == FETCHCOF)
- || (type == FETCHORPHANS);
- // parse update llsd into stuff to do or parse received items.
- S32 depth = 0;
- if (is_fetch && request_body.has("depth"))
- {
- depth = request_body["depth"].asInteger();
- }
- AISUpdate ais_update(update, is_fetch, depth);
+
+ AISUpdate ais_update(update, type, request_body);
ais_update.doUpdate(); // execute the updates in the appropriate order.
LL_DEBUGS("Inventory", "AIS3") << "Elapsed processing: " << timer.getElapsedTimeF32() << LL_ENDL;
}
@@ -833,7 +904,7 @@ void AISAPI::InvokeAISCommandCoro(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t ht
}
LL_DEBUGS("Inventory", "AIS3") << "Result: " << result << LL_ENDL;
- onUpdateReceived("AISCommand", result, type, body);
+ onUpdateReceived(result, type, body);
if (callback && !callback.empty())
{
@@ -900,10 +971,22 @@ void AISAPI::InvokeAISCommandCoro(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t ht
}
//-------------------------------------------------------------------------
-AISUpdate::AISUpdate(const LLSD& update, bool fetch, S32 depth)
-: mFetch(fetch)
-, mFetchDepth(depth)
+AISUpdate::AISUpdate(const LLSD& update, AISAPI::COMMAND_TYPE type, const LLSD& request_body)
+: mType(type)
{
+ mFetch = (type == AISAPI::FETCHITEM)
+ || (type == AISAPI::FETCHCATEGORYCHILDREN)
+ || (type == AISAPI::FETCHCATEGORYCATEGORIES)
+ || (type == AISAPI::FETCHCATEGORYSUBSET)
+ || (type == AISAPI::FETCHCOF)
+ || (type == AISAPI::FETCHORPHANS);
+ // parse update llsd into stuff to do or parse received items.
+ mFetchDepth = MAX_FOLDER_DEPTH_REQUEST;
+ if (mFetch && request_body.has("depth"))
+ {
+ mFetchDepth = request_body["depth"].asInteger();
+ }
+
mTimer.setTimerExpirySec(debugLoggingEnabled("Inventory") ? EXPIRY_SECONDS_DEBUG : EXPIRY_SECONDS_LIVE);
mTimer.start();
parseUpdate(update);
@@ -1023,17 +1106,26 @@ void AISUpdate::parseContent(const LLSD& update)
{
if (update.has("linked_id"))
{
- parseLink(update);
+ parseLink(update, mFetchDepth);
}
else if (update.has("item_id"))
{
parseItem(update);
}
- if (update.has("category_id"))
- {
- parseCategory(update, mFetchDepth);
- }
+ if (mType == AISAPI::FETCHCATEGORYSUBSET)
+ {
+ // initial category is incomplete, don't process it,
+ // go for content instead
+ if (update.has("_embedded"))
+ {
+ parseEmbedded(update["_embedded"], mFetchDepth - 1);
+ }
+ }
+ else if (update.has("category_id"))
+ {
+ parseCategory(update, mFetchDepth);
+ }
else
{
if (update.has("_embedded"))
@@ -1089,7 +1181,7 @@ void AISUpdate::parseItem(const LLSD& item_map)
}
}
-void AISUpdate::parseLink(const LLSD& link_map)
+void AISUpdate::parseLink(const LLSD& link_map, S32 depth)
{
LLUUID item_id = link_map["item_id"].asUUID();
LLPointer<LLViewerInventoryItem> new_link(new LLViewerInventoryItem);
@@ -1145,7 +1237,7 @@ void AISUpdate::parseLink(const LLSD& link_map)
if (link_map.has("_embedded"))
{
- parseEmbedded(link_map["_embedded"], S32_MAX);
+ parseEmbedded(link_map["_embedded"], depth);
}
}
else
@@ -1295,7 +1387,7 @@ void AISUpdate::parseEmbedded(const LLSD& embedded, S32 depth)
if (embedded.has("links")) // _embedded in a category
{
- parseEmbeddedLinks(embedded["links"]);
+ parseEmbeddedLinks(embedded["links"], depth);
}
if (embedded.has("items")) // _embedded in a category
{
@@ -1328,7 +1420,7 @@ void AISUpdate::parseUUIDArray(const LLSD& content, const std::string& name, uui
}
}
-void AISUpdate::parseEmbeddedLinks(const LLSD& links)
+void AISUpdate::parseEmbeddedLinks(const LLSD& links, S32 depth)
{
for(LLSD::map_const_iterator linkit = links.beginMap(),
linkend = links.endMap();
@@ -1342,7 +1434,7 @@ void AISUpdate::parseEmbeddedLinks(const LLSD& links)
}
else
{
- parseLink(link_map);
+ parseLink(link_map, depth);
}
}
}
diff --git a/indra/newview/llaisapi.h b/indra/newview/llaisapi.h
index 6afbbbd16e..691c5db592 100644
--- a/indra/newview/llaisapi.h
+++ b/indra/newview/llaisapi.h
@@ -59,11 +59,11 @@ public:
static void FetchCategoryChildren(const LLUUID &catId, ITEM_TYPE type = AISAPI::ITEM_TYPE::INVENTORY, bool recursive = false, completion_t callback = completion_t(), S32 depth = 0);
static void FetchCategoryChildren(const std::string &identifier, bool recursive = false, completion_t callback = completion_t(), S32 depth = 0);
static void FetchCategoryCategories(const LLUUID &catId, ITEM_TYPE type = AISAPI::ITEM_TYPE::INVENTORY, bool recursive = false, completion_t callback = completion_t(), S32 depth = 0);
+ static void FetchCategorySubset(const LLUUID& catId, const uuid_vec_t specificChildren, ITEM_TYPE type = AISAPI::ITEM_TYPE::INVENTORY, bool recursive = false, completion_t callback = completion_t(), S32 depth = 0);
static void FetchCOF(completion_t callback = completion_t());
static void FetchOrphans(completion_t callback = completion_t() );
static void CopyLibraryCategory(const LLUUID& sourceId, const LLUUID& destId, bool copySubfolders, completion_t callback = completion_t());
-private:
typedef enum {
COPYINVENTORY,
SLAMFOLDER,
@@ -77,10 +77,12 @@ private:
FETCHITEM,
FETCHCATEGORYCHILDREN,
FETCHCATEGORYCATEGORIES,
+ FETCHCATEGORYSUBSET,
FETCHCOF,
FETCHORPHANS,
} COMMAND_TYPE;
+private:
static const std::string INVENTORY_CAP_NAME;
static const std::string LIBRARY_CAP_NAME;
@@ -89,7 +91,7 @@ private:
static void EnqueueAISCommand(const std::string &procName, LLCoprocedureManager::CoProcedure_t proc);
static void onIdle(void *userdata); // launches postponed AIS commands
- static void onUpdateReceived(const std::string& context, const LLSD& update, COMMAND_TYPE type, const LLSD& request_body);
+ static void onUpdateReceived(const LLSD& update, COMMAND_TYPE type, const LLSD& request_body);
static std::string getInvCap();
static std::string getLibCap();
@@ -105,17 +107,17 @@ private:
class AISUpdate
{
public:
- AISUpdate(const LLSD& update, bool fetch, S32 depth);
+ AISUpdate(const LLSD& update, AISAPI::COMMAND_TYPE type, const LLSD& request_body);
void parseUpdate(const LLSD& update);
void parseMeta(const LLSD& update);
void parseContent(const LLSD& update);
void parseUUIDArray(const LLSD& content, const std::string& name, uuid_list_t& ids);
- void parseLink(const LLSD& link_map);
+ void parseLink(const LLSD& link_map, S32 depth);
void parseItem(const LLSD& link_map);
void parseCategory(const LLSD& link_map, S32 depth);
void parseDescendentCount(const LLUUID& category_id, const LLSD& embedded);
void parseEmbedded(const LLSD& embedded, S32 depth);
- void parseEmbeddedLinks(const LLSD& links);
+ void parseEmbeddedLinks(const LLSD& links, S32 depth);
void parseEmbeddedItems(const LLSD& items);
void parseEmbeddedCategories(const LLSD& categories, S32 depth);
void parseEmbeddedItem(const LLSD& item);
@@ -151,6 +153,7 @@ private:
bool mFetch;
S32 mFetchDepth;
LLTimer mTimer;
+ AISAPI::COMMAND_TYPE mType;
};
#endif
diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp
index d79525ec62..4133470973 100644
--- a/indra/newview/llappearancemgr.cpp
+++ b/indra/newview/llappearancemgr.cpp
@@ -4568,7 +4568,18 @@ void callAfterCOFFetch(nullary_func_t cb)
if (cat->getVersion() == LLViewerInventoryCategory::VERSION_UNKNOWN && AISAPI::isAvailable())
{
// Assume that we have no relevant cache. Fetch cof, and items cof's links point to.
- AISAPI::FetchCOF([cb](const LLUUID& id) { cb(); });
+ AISAPI::FetchCOF([cb](const LLUUID& id)
+ {
+ cb();
+ LLUUID cat_id = LLAppearanceMgr::instance().getCOF();
+ LLViewerInventoryCategory* cat = gInventory.getCategory(cat_id);
+ if (cat)
+ {
+ cat->setFetching(LLViewerInventoryCategory::FETCH_NONE);
+ }
+ });
+ // Mark it so that background fetch won't request it if it didn't already
+ cat->setFetching(LLViewerInventoryCategory::FETCH_RECURSIVE);
}
else
{
diff --git a/indra/newview/llinventorymodelbackgroundfetch.cpp b/indra/newview/llinventorymodelbackgroundfetch.cpp
index c5fb40409f..b8fdfab98a 100644
--- a/indra/newview/llinventorymodelbackgroundfetch.cpp
+++ b/indra/newview/llinventorymodelbackgroundfetch.cpp
@@ -299,7 +299,7 @@ void LLInventoryModelBackgroundFetch::start(const LLUUID& id, bool recursive)
// Not only root folder can be massive, but
// most system folders will be requested independently
// so request root folder and content separately
- mFetchFolderQueue.push_front(FetchQueueInfo(gInventory.getRootFolderID(), FT_CONTENT_RECURSIVE));
+ mFetchFolderQueue.push_front(FetchQueueInfo(gInventory.getRootFolderID(), FT_FOLDER_AND_CONTENT));
}
else
{
@@ -455,10 +455,67 @@ void ais_simple_item_callback(const LLUUID& inv_id)
LLInventoryModelBackgroundFetch::instance().incrFetchCount(-1);
}
-void LLInventoryModelBackgroundFetch::onAISFolderCalback(const LLUUID &request_id, const LLUUID &response_id, EFetchType recursion)
+void LLInventoryModelBackgroundFetch::onAISContentCalback(
+ const LLUUID& request_id,
+ const uuid_vec_t& content_ids,
+ const LLUUID& response_id,
+ EFetchType fetch_type)
{
+ // Don't push_front on failure - there is a chance it was fired from inside bulkFetchViaAis
incrFetchFolderCount(-1);
- std::list<LLUUID>::const_iterator found = std::find(mExpectedFolderIds.begin() , mExpectedFolderIds.end(), request_id);
+
+ uuid_vec_t::const_iterator folder_iter = content_ids.begin();
+ uuid_vec_t::const_iterator folder_end = content_ids.end();
+ while (folder_iter != folder_end)
+ {
+ std::list<LLUUID>::const_iterator found = std::find(mExpectedFolderIds.begin(), mExpectedFolderIds.end(), *folder_iter);
+ if (found != mExpectedFolderIds.end())
+ {
+ mExpectedFolderIds.erase(found);
+ }
+
+ LLViewerInventoryCategory* cat(gInventory.getCategory(*folder_iter));
+ if (cat)
+ {
+ cat->setFetching(LLViewerInventoryCategory::FETCH_NONE);
+ }
+ if (response_id.isNull())
+ {
+ // Failed to fetch, get it individually
+ mFetchFolderQueue.push_back(FetchQueueInfo(*folder_iter, FT_RECURSIVE));
+ }
+ else
+ {
+ // push descendant back to verify they are fetched fully (ex: didn't encounter depth limit)
+ LLInventoryModel::cat_array_t* categories(NULL);
+ LLInventoryModel::item_array_t* items(NULL);
+ gInventory.getDirectDescendentsOf(*folder_iter, categories, items);
+ if (categories)
+ {
+ for (LLInventoryModel::cat_array_t::const_iterator it = categories->begin();
+ it != categories->end();
+ ++it)
+ {
+ mFetchFolderQueue.push_back(FetchQueueInfo((*it)->getUUID(), FT_RECURSIVE));
+ }
+ }
+ }
+
+ folder_iter++;
+ }
+
+ if (!mFetchFolderQueue.empty())
+ {
+ mBackgroundFetchActive = true;
+ mFolderFetchActive = true;
+ gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL);
+ }
+}
+void LLInventoryModelBackgroundFetch::onAISFolderCalback(const LLUUID &request_id, const LLUUID &response_id, EFetchType fetch_type)
+{
+ // Don't push_front on failure - there is a chance it was fired from inside bulkFetchViaAis
+ incrFetchFolderCount(-1);
+ std::list<LLUUID>::const_iterator found = std::find(mExpectedFolderIds.begin(), mExpectedFolderIds.end(), request_id);
if (found != mExpectedFolderIds.end())
{
mExpectedFolderIds.erase(found);
@@ -480,32 +537,34 @@ void LLInventoryModelBackgroundFetch::onAISFolderCalback(const LLUUID &request_i
if (response_id.isNull()) // Failure
{
LL_DEBUGS(LOG_INV , "AIS3") << "Failure response for folder " << request_id << LL_ENDL;
- if (recursion == FT_RECURSIVE)
+ if (fetch_type == FT_RECURSIVE)
{
// A full recursive request failed.
// Try requesting folder and nested content separately
- mBackgroundFetchActive = true;
- mFolderFetchActive = true;
- mFetchFolderQueue.push_front(FetchQueueInfo(request_id, FT_CONTENT_RECURSIVE));
- gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL);
+ mFetchFolderQueue.push_back(FetchQueueInfo(request_id, FT_FOLDER_AND_CONTENT));
}
- else if (recursion == FT_CONTENT_RECURSIVE)
+ else if (fetch_type == FT_FOLDER_AND_CONTENT)
{
LL_WARNS() << "Failed to download folder: " << request_id << " Requesting known content separately" << LL_ENDL;
- request_descendants = true;
+ mFetchFolderQueue.push_back(FetchQueueInfo(request_id, FT_CONTENT_RECURSIVE));
}
}
else
{
- if (recursion == FT_CONTENT_RECURSIVE || recursion == FT_RECURSIVE)
+ if (fetch_type == FT_RECURSIVE)
{
- // Got the folder, now recursively request content
+ // Got the folder and content, now verify content
// Request content even for FT_RECURSIVE in case of changes, failures
// or if depth limit gets imlemented.
// This shouldn't redownload folders if they already have version
request_descendants = true;
LL_DEBUGS(LOG_INV, "AIS3") << "Got folder " << request_id << ". Requesting content" << LL_ENDL;
}
+ else if (fetch_type == FT_FOLDER_AND_CONTENT)
+ {
+ // readd folder for content request
+ mFetchFolderQueue.push_front(FetchQueueInfo(request_id, FT_CONTENT_RECURSIVE));
+ }
else
{
LL_DEBUGS(LOG_INV, "AIS3") << "Got folder " << request_id << "." << LL_ENDL;
@@ -524,17 +583,18 @@ void LLInventoryModelBackgroundFetch::onAISFolderCalback(const LLUUID &request_i
it != categories->end();
++it)
{
- mFetchFolderQueue.push_front(FetchQueueInfo((*it)->getUUID(), FT_RECURSIVE));
- }
- if (!mFetchFolderQueue.empty())
- {
- mBackgroundFetchActive = true;
- mFolderFetchActive = true;
- gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL);
+ mFetchFolderQueue.push_back(FetchQueueInfo((*it)->getUUID(), FT_RECURSIVE));
}
}
}
+ if (!mFetchFolderQueue.empty())
+ {
+ mBackgroundFetchActive = true;
+ mFolderFetchActive = true;
+ gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL);
+ }
+
// done
LLViewerInventoryCategory * cat(gInventory.getCategory(request_id));
if (cat)
@@ -555,9 +615,9 @@ void LLInventoryModelBackgroundFetch::bulkFetchViaAis()
}
static LLCachedControl<U32> ais_pool(gSavedSettings, "PoolSizeAIS", 20);
- // Don't have too many requests at once
+ // Don't have too many requests at once, AIS throttles
// Reserve one request for actions outside of fetch (like renames)
- const U32 max_concurrent_fetches = llmax(1, ais_pool - 1);
+ const U32 max_concurrent_fetches = llclamp(ais_pool - 1, 1, 50);
if (mFetchCount >= max_concurrent_fetches)
{
@@ -663,10 +723,97 @@ void LLInventoryModelBackgroundFetch::bulkFetchViaAis(const FetchQueueInfo& fetc
LLViewerInventoryCategory * cat(gInventory.getCategory(cat_id));
if (cat)
{
- if (LLViewerInventoryCategory::VERSION_UNKNOWN == cat->getVersion() || fetch_info.mFetchType == FT_FORCED)
+ if (fetch_info.mFetchType == FT_CONTENT_RECURSIVE)
+ {
+ // fetch content only, ignore cat itself
+ uuid_vec_t children;
+ LLInventoryModel::cat_array_t* categories(NULL);
+ LLInventoryModel::item_array_t* items(NULL);
+ gInventory.getDirectDescendentsOf(cat_id, categories, items);
+
+ LLViewerInventoryCategory::EFetchType target_state =
+ fetch_info.mFetchType > FT_CONTENT_RECURSIVE
+ ? LLViewerInventoryCategory::FETCH_RECURSIVE
+ : LLViewerInventoryCategory::FETCH_NORMAL;
+ // technically limit is 'as many as you can put into url', but for now stop at 10
+ const S32 batch_limit = 10;
+ bool content_done = true;
+
+ for (LLInventoryModel::cat_array_t::iterator it = categories->begin();
+ it != categories->end();
+ ++it)
+ {
+ LLViewerInventoryCategory* child_cat = (*it);
+ if (LLViewerInventoryCategory::VERSION_UNKNOWN != child_cat->getVersion()
+ || child_cat->getFetching() >= target_state)
+ {
+ // push it back to verify everything inside is fetched
+ mFetchFolderQueue.push_back(FetchQueueInfo((*it)->getUUID(), FT_RECURSIVE));
+ continue;
+ }
+
+ if (child_cat->getPreferredType() == LLFolderType::FT_MARKETPLACE_LISTINGS)
+ {
+ // special case
+ content_done = false;
+ if (children.empty())
+ {
+ // fetch marketplace alone
+ children.push_back(child_cat->getUUID());
+ mExpectedFolderIds.push_back(child_cat->getUUID());
+ child_cat->setFetching(target_state);
+ break;
+ }
+ else
+ {
+ // fetch marketplace alone next run
+ continue;
+ }
+ }
+
+ children.push_back(child_cat->getUUID());
+ mExpectedFolderIds.push_back(child_cat->getUUID());
+ child_cat->setFetching(target_state);
+
+ if (children.size() >= batch_limit)
+ {
+ content_done = false;
+ break;
+ }
+ }
+
+ if (!children.empty())
+ {
+ // increment before call in case of immediate callback
+ incrFetchFolderCount(1);
+
+ EFetchType type = fetch_info.mFetchType;
+ LLUUID cat_id = cat->getUUID(); // need a copy for lambda
+ AISAPI::completion_t cb = [cat_id, children, type](const LLUUID& response_id)
+ {
+ LLInventoryModelBackgroundFetch::instance().onAISContentCalback(cat_id, children, response_id, type);
+ };
+
+ AISAPI::ITEM_TYPE item_type = AISAPI::INVENTORY;
+ if (ALEXANDRIA_LINDEN_ID == cat->getOwnerID())
+ {
+ item_type = AISAPI::LIBRARY;
+ }
+
+ AISAPI::FetchCategorySubset(cat_id, children, item_type, true, cb, 0);
+ }
+
+ if (!content_done)
+ {
+ // send it back to get the rest
+ mFetchFolderQueue.push_back(FetchQueueInfo(cat_id, FT_CONTENT_RECURSIVE));
+ }
+ }
+ else if (LLViewerInventoryCategory::VERSION_UNKNOWN == cat->getVersion()
+ || fetch_info.mFetchType == FT_FORCED)
{
LLViewerInventoryCategory::EFetchType target_state =
- fetch_info.mFetchType >= FT_CONTENT_RECURSIVE
+ fetch_info.mFetchType > FT_CONTENT_RECURSIVE
? LLViewerInventoryCategory::FETCH_RECURSIVE
: LLViewerInventoryCategory::FETCH_NORMAL;
// start again if we did a non-recursive fetch before
@@ -711,7 +858,7 @@ void LLInventoryModelBackgroundFetch::bulkFetchViaAis(const FetchQueueInfo& fetc
}
}
}
- } // else?
+ } // else try to fetch folder either way?
}
}
else
diff --git a/indra/newview/llinventorymodelbackgroundfetch.h b/indra/newview/llinventorymodelbackgroundfetch.h
index 363d04486d..1fd7426312 100644
--- a/indra/newview/llinventorymodelbackgroundfetch.h
+++ b/indra/newview/llinventorymodelbackgroundfetch.h
@@ -82,8 +82,9 @@ protected:
typedef enum {
FT_DEFAULT = 0,
- FT_FORCED, // request even if already loaded
+ FT_FORCED, // request non-recursively even if already loaded
FT_CONTENT_RECURSIVE, // request content recursively
+ FT_FOLDER_AND_CONTENT, // request content recursively
FT_RECURSIVE, // request everything recursively
} EFetchType;
struct FetchQueueInfo
@@ -100,7 +101,8 @@ protected:
};
typedef std::deque<FetchQueueInfo> fetch_queue_t;
- void onAISFolderCalback(const LLUUID &request_id, const LLUUID &response_id, EFetchType recursion);
+ void onAISContentCalback(const LLUUID& request_id, const uuid_vec_t &content_ids, const LLUUID& response_id, EFetchType fetch_type);
+ void onAISFolderCalback(const LLUUID &request_id, const LLUUID &response_id, EFetchType fetch_type);
void bulkFetchViaAis();
void bulkFetchViaAis(const FetchQueueInfo& fetch_info);
void bulkFetch();