Inv fetch migrated from LLInventoryModel to LLInventoryModelBackgroundFetch singleton.
This commit is contained in:
@@ -78,22 +78,6 @@
|
||||
#include "process.h"
|
||||
#endif
|
||||
|
||||
const F32 MAX_TIME_FOR_SINGLE_FETCH = 10.f;
|
||||
const S32 MAX_FETCH_RETRIES = 10;
|
||||
BOOL LLInventoryModel::sBackgroundFetchActive = FALSE;
|
||||
BOOL LLInventoryModel::sAllFoldersFetched = FALSE;
|
||||
BOOL LLInventoryModel::sFullFetchStarted = FALSE;
|
||||
S32 LLInventoryModel::sNumFetchRetries = 0;
|
||||
F32 LLInventoryModel::sMinTimeBetweenFetches = 0.3f;
|
||||
F32 LLInventoryModel::sMaxTimeBetweenFetches = 10.f;
|
||||
BOOL LLInventoryModel::sTimelyFetchPending = FALSE;
|
||||
LLFrameTimer LLInventoryModel::sFetchTimer;
|
||||
S16 LLInventoryModel::sBulkFetchCount = 0;
|
||||
|
||||
// RN: for some reason, using std::queue in the header file confuses the compiler which things it's an xmlrpc_queue
|
||||
static std::deque<LLUUID> sFetchQueue;
|
||||
|
||||
|
||||
// Increment this if the inventory contents change in a non-backwards-compatible way.
|
||||
// For viewers with link items support, former caches are incorrect.
|
||||
const S32 LLInventoryModel::sCurrentInvCacheVersion = 2;
|
||||
@@ -1384,523 +1368,6 @@ bool LLInventoryModel::fetchDescendentsOf(const LLUUID& folder_id) const
|
||||
return cat->fetchDescendents();
|
||||
}
|
||||
|
||||
//Initialize statics.
|
||||
bool LLInventoryModel::isBulkFetchProcessingComplete()
|
||||
{
|
||||
return ( (sFetchQueue.empty()
|
||||
&& sBulkFetchCount<=0) ? TRUE : FALSE ) ;
|
||||
}
|
||||
|
||||
class fetchDescendentsResponder: public LLHTTPClient::Responder
|
||||
{
|
||||
public:
|
||||
fetchDescendentsResponder(const LLSD& request_sd) : mRequestSD(request_sd) {};
|
||||
//fetchDescendentsResponder() {};
|
||||
void result(const LLSD& content);
|
||||
void error(U32 status, const std::string& reason);
|
||||
public:
|
||||
typedef std::vector<LLViewerInventoryCategory*> folder_ref_t;
|
||||
protected:
|
||||
LLSD mRequestSD;
|
||||
};
|
||||
|
||||
//If we get back a normal response, handle it here
|
||||
// Note: this is the handler for WebFetchInventoryDescendents and agent/inventory caps
|
||||
void fetchDescendentsResponder::result(const LLSD& content)
|
||||
{
|
||||
if (content.has("folders"))
|
||||
{
|
||||
|
||||
for(LLSD::array_const_iterator folder_it = content["folders"].beginArray();
|
||||
folder_it != content["folders"].endArray();
|
||||
++folder_it)
|
||||
{
|
||||
LLSD folder_sd = *folder_it;
|
||||
|
||||
|
||||
//LLUUID agent_id = folder_sd["agent_id"];
|
||||
|
||||
//if(agent_id != gAgent.getID()) //This should never happen.
|
||||
//{
|
||||
// llwarns << "Got a UpdateInventoryItem for the wrong agent."
|
||||
// << llendl;
|
||||
// break;
|
||||
//}
|
||||
|
||||
LLUUID parent_id = folder_sd["folder_id"];
|
||||
LLUUID owner_id = folder_sd["owner_id"];
|
||||
S32 version = (S32)folder_sd["version"].asInteger();
|
||||
S32 descendents = (S32)folder_sd["descendents"].asInteger();
|
||||
LLPointer<LLViewerInventoryCategory> tcategory = new LLViewerInventoryCategory(owner_id);
|
||||
|
||||
if (parent_id.isNull())
|
||||
{
|
||||
LLPointer<LLViewerInventoryItem> titem = new LLViewerInventoryItem;
|
||||
for(LLSD::array_const_iterator item_it = folder_sd["items"].beginArray();
|
||||
item_it != folder_sd["items"].endArray();
|
||||
++item_it)
|
||||
{
|
||||
LLUUID lost_uuid = gInventory.findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND);
|
||||
if (lost_uuid.notNull())
|
||||
{
|
||||
LLSD item = *item_it;
|
||||
titem->unpackMessage(item);
|
||||
|
||||
LLInventoryModel::update_list_t update;
|
||||
LLInventoryModel::LLCategoryUpdate new_folder(lost_uuid, 1);
|
||||
update.push_back(new_folder);
|
||||
gInventory.accountForUpdate(update);
|
||||
|
||||
titem->setParent(lost_uuid);
|
||||
titem->updateParentOnServer(FALSE);
|
||||
gInventory.updateItem(titem);
|
||||
gInventory.notifyObservers();
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LLViewerInventoryCategory* pcat = gInventory.getCategory(parent_id);
|
||||
if (!pcat)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
for(LLSD::array_const_iterator category_it = folder_sd["categories"].beginArray();
|
||||
category_it != folder_sd["categories"].endArray();
|
||||
++category_it)
|
||||
{
|
||||
LLSD category = *category_it;
|
||||
tcategory->fromLLSD(category);
|
||||
|
||||
if (LLInventoryModel::sFullFetchStarted)
|
||||
{
|
||||
sFetchQueue.push_back(tcategory->getUUID());
|
||||
}
|
||||
else if ( !gInventory.isCategoryComplete(tcategory->getUUID()) )
|
||||
{
|
||||
gInventory.updateCategory(tcategory);
|
||||
}
|
||||
|
||||
}
|
||||
LLPointer<LLViewerInventoryItem> titem = new LLViewerInventoryItem;
|
||||
for(LLSD::array_const_iterator item_it = folder_sd["items"].beginArray();
|
||||
item_it != folder_sd["items"].endArray();
|
||||
++item_it)
|
||||
{
|
||||
LLSD item = *item_it;
|
||||
titem->unpackMessage(item);
|
||||
|
||||
gInventory.updateItem(titem);
|
||||
}
|
||||
|
||||
// set version and descendentcount according to message.
|
||||
LLViewerInventoryCategory* cat = gInventory.getCategory(parent_id);
|
||||
if(cat)
|
||||
{
|
||||
cat->setVersion(version);
|
||||
cat->setDescendentCount(descendents);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (content.has("bad_folders"))
|
||||
{
|
||||
for(LLSD::array_const_iterator folder_it = content["bad_folders"].beginArray();
|
||||
folder_it != content["bad_folders"].endArray();
|
||||
++folder_it)
|
||||
{
|
||||
LLSD folder_sd = *folder_it;
|
||||
|
||||
//These folders failed on the dataserver. We probably don't want to retry them.
|
||||
LL_INFOS("Inventory") << "Folder " << folder_sd["folder_id"].asString()
|
||||
<< "Error: " << folder_sd["error"].asString() << LL_ENDL;
|
||||
}
|
||||
}
|
||||
|
||||
LLInventoryModel::incrBulkFetch(-1);
|
||||
|
||||
if (LLInventoryModel::isBulkFetchProcessingComplete())
|
||||
{
|
||||
LL_DEBUGS("Inventory") << "Inventory fetch completed" << LL_ENDL;
|
||||
if (LLInventoryModel::sFullFetchStarted)
|
||||
{
|
||||
LLInventoryModel::sAllFoldersFetched = TRUE;
|
||||
}
|
||||
LLInventoryModel::stopBackgroundFetch();
|
||||
}
|
||||
|
||||
gInventory.notifyObservers();
|
||||
}
|
||||
|
||||
//If we get back an error (not found, etc...), handle it here
|
||||
void fetchDescendentsResponder::error(U32 status, const std::string& reason)
|
||||
{
|
||||
LL_INFOS("Inventory") << "fetchDescendentsResponder::error "
|
||||
<< status << ": " << reason << LL_ENDL;
|
||||
|
||||
LLInventoryModel::incrBulkFetch(-1);
|
||||
|
||||
if (status==499) //timed out. Let's be awesome!
|
||||
{
|
||||
for(LLSD::array_const_iterator folder_it = mRequestSD["folders"].beginArray();
|
||||
folder_it != mRequestSD["folders"].endArray();
|
||||
++folder_it)
|
||||
{
|
||||
LLSD folder_sd = *folder_it;
|
||||
LLUUID folder_id = folder_sd["folder_id"];
|
||||
sFetchQueue.push_front(folder_id);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (LLInventoryModel::isBulkFetchProcessingComplete())
|
||||
{
|
||||
if (LLInventoryModel::sFullFetchStarted)
|
||||
{
|
||||
LLInventoryModel::sAllFoldersFetched = TRUE;
|
||||
}
|
||||
LLInventoryModel::stopBackgroundFetch();
|
||||
}
|
||||
}
|
||||
gInventory.notifyObservers();
|
||||
}
|
||||
|
||||
//static Bundle up a bunch of requests to send all at once.
|
||||
void LLInventoryModel::bulkFetch(std::string url)
|
||||
{
|
||||
//Background fetch is called from gIdleCallbacks in a loop until background fetch is stopped.
|
||||
//If there are items in sFetchQueue, we want to check the time since the last bulkFetch was
|
||||
//sent. If it exceeds our retry time, go ahead and fire off another batch.
|
||||
//Stopbackgroundfetch will be run from the Responder instead of here.
|
||||
|
||||
S16 max_concurrent_fetches=8;
|
||||
F32 new_min_time = 0.5f; //HACK! Clean this up when old code goes away entirely.
|
||||
if (sMinTimeBetweenFetches < new_min_time) sMinTimeBetweenFetches=new_min_time; //HACK! See above.
|
||||
|
||||
if(gDisconnected
|
||||
|| sBulkFetchCount > max_concurrent_fetches
|
||||
|| sFetchTimer.getElapsedTimeF32() < sMinTimeBetweenFetches)
|
||||
{
|
||||
return; // just bail if we are disconnected.
|
||||
}
|
||||
|
||||
U32 folder_count=0;
|
||||
U32 max_batch_size=5;
|
||||
|
||||
U32 sort_order = gSavedSettings.getU32("InventorySortOrder") & 0x1;
|
||||
|
||||
LLSD body;
|
||||
LLSD body_lib;
|
||||
while( !(sFetchQueue.empty() ) && (folder_count < max_batch_size) )
|
||||
{
|
||||
if (sFetchQueue.front().isNull()) //DEV-17797
|
||||
{
|
||||
LLSD folder_sd;
|
||||
folder_sd["folder_id"] = LLUUID::null.asString();
|
||||
folder_sd["owner_id"] = gAgent.getID();
|
||||
folder_sd["sort_order"] = (LLSD::Integer)sort_order;
|
||||
folder_sd["fetch_folders"] = (LLSD::Boolean)FALSE;
|
||||
folder_sd["fetch_items"] = (LLSD::Boolean)TRUE;
|
||||
body["folders"].append(folder_sd);
|
||||
folder_count++;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
|
||||
LLViewerInventoryCategory* cat = gInventory.getCategory(sFetchQueue.front());
|
||||
|
||||
if (cat)
|
||||
{
|
||||
// <edit> Pre-emptive strike
|
||||
//if(!(gInventory.isObjectDescendentOf(cat->getUUID(), gSystemFolderRoot)))
|
||||
if(true)
|
||||
{
|
||||
// </edit>
|
||||
if ( LLViewerInventoryCategory::VERSION_UNKNOWN == cat->getVersion())
|
||||
{
|
||||
LLSD folder_sd;
|
||||
folder_sd["folder_id"] = cat->getUUID();
|
||||
folder_sd["owner_id"] = cat->getOwnerID();
|
||||
folder_sd["sort_order"] = (LLSD::Integer)sort_order;
|
||||
folder_sd["fetch_folders"] = TRUE; //(LLSD::Boolean)sFullFetchStarted;
|
||||
folder_sd["fetch_items"] = (LLSD::Boolean)TRUE;
|
||||
|
||||
LL_DEBUGS("Inventory") << " fetching "<<cat->getUUID()<<" with cat owner "<<cat->getOwnerID()<<" and agent" << gAgent.getID() << LL_ENDL;
|
||||
if (ALEXANDRIA_LINDEN_ID == cat->getOwnerID())
|
||||
body_lib["folders"].append(folder_sd);
|
||||
else
|
||||
body["folders"].append(folder_sd);
|
||||
folder_count++;
|
||||
}
|
||||
if (sFullFetchStarted)
|
||||
{ //Already have this folder but append child folders to list.
|
||||
// add all children to queue
|
||||
parent_cat_map_t::iterator cat_it = gInventory.mParentChildCategoryTree.find(cat->getUUID());
|
||||
if (cat_it != gInventory.mParentChildCategoryTree.end())
|
||||
{
|
||||
cat_array_t* child_categories = cat_it->second;
|
||||
|
||||
for (S32 child_num = 0; child_num < child_categories->count(); child_num++)
|
||||
{
|
||||
sFetchQueue.push_back(child_categories->get(child_num)->getUUID());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
// <edit>
|
||||
}
|
||||
// </edit>
|
||||
}
|
||||
}
|
||||
sFetchQueue.pop_front();
|
||||
}
|
||||
|
||||
if (folder_count > 0)
|
||||
{
|
||||
sBulkFetchCount++;
|
||||
if (body["folders"].size())
|
||||
{
|
||||
LLHTTPClient::post(url, body, new fetchDescendentsResponder(body),300.0);
|
||||
}
|
||||
if (body_lib["folders"].size())
|
||||
{
|
||||
std::string url_lib;
|
||||
url_lib = gAgent.getRegion()->getCapability("FetchLibDescendents");
|
||||
LLHTTPClient::post(url_lib, body_lib, new fetchDescendentsResponder(body_lib),300.0);
|
||||
}
|
||||
sFetchTimer.reset();
|
||||
}
|
||||
else if (isBulkFetchProcessingComplete())
|
||||
{
|
||||
if (sFullFetchStarted)
|
||||
{
|
||||
sAllFoldersFetched = TRUE;
|
||||
}
|
||||
stopBackgroundFetch();
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
bool LLInventoryModel::isEverythingFetched()
|
||||
{
|
||||
return (sAllFoldersFetched ? true : false);
|
||||
}
|
||||
|
||||
//static
|
||||
BOOL LLInventoryModel::backgroundFetchActive()
|
||||
{
|
||||
return sBackgroundFetchActive;
|
||||
}
|
||||
|
||||
//static
|
||||
void LLInventoryModel::startBackgroundFetch(const LLUUID& cat_id)
|
||||
{
|
||||
if (!sAllFoldersFetched)
|
||||
{
|
||||
if (cat_id.isNull())
|
||||
{
|
||||
if (!sFullFetchStarted)
|
||||
{
|
||||
sFullFetchStarted = TRUE;
|
||||
sFetchQueue.push_back(gInventory.getLibraryRootFolderID());
|
||||
sFetchQueue.push_back(gInventory.getRootFolderID());
|
||||
if (!sBackgroundFetchActive)
|
||||
{
|
||||
sBackgroundFetchActive = TRUE;
|
||||
gIdleCallbacks.addFunction(&LLInventoryModel::backgroundFetch, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// specific folder requests go to front of queue
|
||||
// Remove it from the queue first, to avoid getting it twice.
|
||||
if (!sFetchQueue.empty() && sFetchQueue.front() != cat_id)
|
||||
{
|
||||
std::deque<LLUUID>::iterator old_entry = std::find(sFetchQueue.begin(), sFetchQueue.end(), cat_id);
|
||||
if (old_entry != sFetchQueue.end())
|
||||
{
|
||||
sFetchQueue.erase(old_entry);
|
||||
}
|
||||
}
|
||||
sFetchQueue.push_front(cat_id);
|
||||
if (!sBackgroundFetchActive)
|
||||
{
|
||||
sBackgroundFetchActive = TRUE;
|
||||
gIdleCallbacks.addFunction(&LLInventoryModel::backgroundFetch, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//static
|
||||
void LLInventoryModel::findLostItems()
|
||||
{
|
||||
sFetchQueue.push_back(LLUUID::null);
|
||||
if (!sBackgroundFetchActive)
|
||||
{
|
||||
sBackgroundFetchActive = TRUE;
|
||||
gIdleCallbacks.addFunction(&LLInventoryModel::backgroundFetch, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
//static
|
||||
void LLInventoryModel::stopBackgroundFetch()
|
||||
{
|
||||
if (sBackgroundFetchActive)
|
||||
{
|
||||
sBackgroundFetchActive = FALSE;
|
||||
gIdleCallbacks.deleteFunction(&LLInventoryModel::backgroundFetch, NULL);
|
||||
sBulkFetchCount=0;
|
||||
sMinTimeBetweenFetches=0.0f;
|
||||
if (!sAllFoldersFetched)
|
||||
{
|
||||
// We didn't finish this, so set it to FALSE in order to be able to start it again.
|
||||
sFullFetchStarted=FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//static
|
||||
void LLInventoryModel::backgroundFetch(void*)
|
||||
{
|
||||
if (sBackgroundFetchActive && gAgent.getRegion())
|
||||
{
|
||||
// If we'll be using the capability, we'll be sending batches and the background thing isn't as important.
|
||||
std::string url = gAgent.getRegion()->getCapability("FetchInventoryDescendents");
|
||||
if (false /*gSavedSettings.getBOOL("UseHTTPInventory")*/ && !url.empty())
|
||||
{
|
||||
bulkFetch(url);
|
||||
return;
|
||||
}
|
||||
|
||||
#if 1
|
||||
//DEPRECATED OLD CODE FOLLOWS.
|
||||
// no more categories to fetch, stop fetch process
|
||||
if (sFetchQueue.empty())
|
||||
{
|
||||
llinfos << "Inventory fetch completed" << llendl;
|
||||
if (sFullFetchStarted)
|
||||
{
|
||||
sAllFoldersFetched = TRUE;
|
||||
}
|
||||
stopBackgroundFetch();
|
||||
return;
|
||||
}
|
||||
|
||||
F32 fast_fetch_time = lerp(sMinTimeBetweenFetches, sMaxTimeBetweenFetches, 0.1f);
|
||||
F32 slow_fetch_time = lerp(sMinTimeBetweenFetches, sMaxTimeBetweenFetches, 0.5f);
|
||||
if (sTimelyFetchPending && sFetchTimer.getElapsedTimeF32() > slow_fetch_time)
|
||||
{
|
||||
// double timeouts on failure
|
||||
sMinTimeBetweenFetches = llmin(sMinTimeBetweenFetches * 2.f, 10.f);
|
||||
sMaxTimeBetweenFetches = llmin(sMaxTimeBetweenFetches * 2.f, 120.f);
|
||||
llinfos << "Inventory fetch times grown to (" << sMinTimeBetweenFetches << ", " << sMaxTimeBetweenFetches << ")" << llendl;
|
||||
// fetch is no longer considered "timely" although we will wait for full time-out
|
||||
sTimelyFetchPending = FALSE;
|
||||
}
|
||||
|
||||
while(1)
|
||||
{
|
||||
if (sFetchQueue.empty())
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if(gDisconnected)
|
||||
{
|
||||
// just bail if we are disconnected.
|
||||
break;
|
||||
}
|
||||
|
||||
LLViewerInventoryCategory* cat = gInventory.getCategory(sFetchQueue.front());
|
||||
|
||||
// category has been deleted, remove from queue.
|
||||
if (!cat)
|
||||
{
|
||||
sFetchQueue.pop_front();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (sFetchTimer.getElapsedTimeF32() > sMinTimeBetweenFetches &&
|
||||
LLViewerInventoryCategory::VERSION_UNKNOWN == cat->getVersion())
|
||||
{
|
||||
// category exists but has no children yet, fetch the descendants
|
||||
// for now, just request every time and rely on retry timer to throttle
|
||||
if (cat->fetchDescendents())
|
||||
{
|
||||
sFetchTimer.reset();
|
||||
sTimelyFetchPending = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
// The catagory also tracks if it has expired and here it says it hasn't
|
||||
// yet. Get out of here because nothing is going to happen until we
|
||||
// update the timers.
|
||||
break;
|
||||
}
|
||||
}
|
||||
// do I have all my children?
|
||||
else if (gInventory.isCategoryComplete(sFetchQueue.front()))
|
||||
{
|
||||
// finished with this category, remove from queue
|
||||
sFetchQueue.pop_front();
|
||||
|
||||
// add all children to queue
|
||||
parent_cat_map_t::iterator cat_it = gInventory.mParentChildCategoryTree.find(cat->getUUID());
|
||||
if (cat_it != gInventory.mParentChildCategoryTree.end())
|
||||
{
|
||||
cat_array_t* child_categories = cat_it->second;
|
||||
|
||||
for (S32 child_num = 0; child_num < child_categories->count(); child_num++)
|
||||
{
|
||||
sFetchQueue.push_back(child_categories->get(child_num)->getUUID());
|
||||
}
|
||||
}
|
||||
|
||||
// we received a response in less than the fast time
|
||||
if (sTimelyFetchPending && sFetchTimer.getElapsedTimeF32() < fast_fetch_time)
|
||||
{
|
||||
// shrink timeouts based on success
|
||||
sMinTimeBetweenFetches = llmax(sMinTimeBetweenFetches * 0.8f, 0.3f);
|
||||
sMaxTimeBetweenFetches = llmax(sMaxTimeBetweenFetches * 0.8f, 10.f);
|
||||
//llinfos << "Inventory fetch times shrunk to (" << sMinTimeBetweenFetches << ", " << sMaxTimeBetweenFetches << ")" << llendl;
|
||||
}
|
||||
|
||||
sTimelyFetchPending = FALSE;
|
||||
continue;
|
||||
}
|
||||
else if (sFetchTimer.getElapsedTimeF32() > sMaxTimeBetweenFetches)
|
||||
{
|
||||
// received first packet, but our num descendants does not match db's num descendants
|
||||
// so try again later
|
||||
LLUUID fetch_id = sFetchQueue.front();
|
||||
sFetchQueue.pop_front();
|
||||
|
||||
if (sNumFetchRetries++ < MAX_FETCH_RETRIES)
|
||||
{
|
||||
// push on back of queue
|
||||
sFetchQueue.push_back(fetch_id);
|
||||
}
|
||||
sTimelyFetchPending = FALSE;
|
||||
sFetchTimer.reset();
|
||||
break;
|
||||
}
|
||||
|
||||
// not enough time has elapsed to do a new fetch
|
||||
break;
|
||||
}
|
||||
|
||||
//
|
||||
// DEPRECATED OLD CODE
|
||||
//--------------------------------------------------------------------------------
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void LLInventoryModel::cache(
|
||||
const LLUUID& parent_folder_id,
|
||||
const LLUUID& agent_id)
|
||||
|
||||
Reference in New Issue
Block a user