Skip to content
Snippets Groups Projects
Commit 116c4275 authored by Loren Shih's avatar Loren Shih
Browse files

Rename to remove camelcase from llinventorymodelbackground files.

parent 715e38fb
No related branches found
No related tags found
No related merge requests found
/**
* @file llinventorymodel.cpp
* @brief Implementation of the inventory model used to track agent inventory.
*
* $LicenseInfo:firstyear=2002&license=viewergpl$
*
* Copyright (c) 2002-2009, Linden Research, Inc.
*
* Second Life Viewer Source Code
* The source code in this file ("Source Code") is provided by Linden Lab
* to you under the terms of the GNU General Public License, version 2.0
* ("GPL"), unless you have obtained a separate licensing agreement
* ("Other License"), formally executed by you and Linden Lab. Terms of
* the GPL can be found in doc/GPL-license.txt in this distribution, or
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
*
* There are special exceptions to the terms and conditions of the GPL as
* it is applied to this Source Code. View the full text of the exception
* in the file doc/FLOSS-exception.txt in this software distribution, or
* online at
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
*
* By copying, modifying or distributing this software, you acknowledge
* that you have read and understood your obligations described above,
* and agree to abide by those obligations.
*
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
* COMPLETENESS OR PERFORMANCE.
* $/LicenseInfo$
*/
#include "llviewerprecompiledheaders.h"
#include "llinventorymodelbackgroundfetch.h"
// Seraph clean this up
#include "llagent.h"
#include "llinventorypanel.h"
#include "llviewercontrol.h"
#include "llviewermessage.h"
#include "llviewerwindow.h"
#include "llappviewer.h"
#include "llviewerregion.h"
#include "llcallbacklist.h"
const F32 MAX_TIME_FOR_SINGLE_FETCH = 10.f;
const S32 MAX_FETCH_RETRIES = 10;
// RN: for some reason, using std::queue in the header file confuses the compiler which thinks it's an xmlrpc_queue
static std::deque<LLUUID> sFetchQueue;
bool fetchQueueContainsNoDescendentsOf(const LLUUID& cat_id)
{
for (std::deque<LLUUID>::iterator it = sFetchQueue.begin();
it != sFetchQueue.end(); ++it)
{
const LLUUID& fetch_id = *it;
if (gInventory.isObjectDescendentOf(fetch_id, cat_id))
return false;
}
return true;
}
LLInventoryModelBackgroundFetch::LLInventoryModelBackgroundFetch() :
mBackgroundFetchActive(FALSE),
mAllFoldersFetched(FALSE),
mInventoryFetchStarted(FALSE),
mLibraryFetchStarted(FALSE),
mNumFetchRetries(0),
mMinTimeBetweenFetches(0.3f),
mMaxTimeBetweenFetches(10.f),
mTimelyFetchPending(FALSE),
mBulkFetchCount(0)
{
}
LLInventoryModelBackgroundFetch::~LLInventoryModelBackgroundFetch()
{
}
bool LLInventoryModelBackgroundFetch::isBulkFetchProcessingComplete()
{
return sFetchQueue.empty() && mBulkFetchCount<=0;
}
bool LLInventoryModelBackgroundFetch::libraryFetchStarted()
{
return mLibraryFetchStarted;
}
bool LLInventoryModelBackgroundFetch::libraryFetchCompleted()
{
return libraryFetchStarted() && fetchQueueContainsNoDescendentsOf(gInventory.getLibraryRootFolderID());
}
bool LLInventoryModelBackgroundFetch::libraryFetchInProgress()
{
return libraryFetchStarted() && !libraryFetchCompleted();
}
bool LLInventoryModelBackgroundFetch::inventoryFetchStarted()
{
return mInventoryFetchStarted;
}
bool LLInventoryModelBackgroundFetch::inventoryFetchCompleted()
{
return inventoryFetchStarted() && fetchQueueContainsNoDescendentsOf(gInventory.getRootFolderID());
}
bool LLInventoryModelBackgroundFetch::inventoryFetchInProgress()
{
return inventoryFetchStarted() && !inventoryFetchCompleted();
}
bool LLInventoryModelBackgroundFetch::isEverythingFetched()
{
return mAllFoldersFetched;
}
BOOL LLInventoryModelBackgroundFetch::backgroundFetchActive()
{
return mBackgroundFetchActive;
}
void LLInventoryModelBackgroundFetch::start(const LLUUID& cat_id)
{
if (!mAllFoldersFetched)
{
mBackgroundFetchActive = TRUE;
if (cat_id.isNull())
{
if (!mInventoryFetchStarted)
{
mInventoryFetchStarted = TRUE;
sFetchQueue.push_back(gInventory.getRootFolderID());
gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL);
}
if (!mLibraryFetchStarted)
{
mLibraryFetchStarted = TRUE;
sFetchQueue.push_back(gInventory.getLibraryRootFolderID());
gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL);
}
}
else
{
// specific folder requests go to front of queue
if (sFetchQueue.empty() || sFetchQueue.front() != cat_id)
{
sFetchQueue.push_front(cat_id);
gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL);
}
if (cat_id == gInventory.getLibraryRootFolderID())
{
mLibraryFetchStarted = TRUE;
}
if (cat_id == gInventory.getRootFolderID())
{
mInventoryFetchStarted = TRUE;
}
}
}
}
void LLInventoryModelBackgroundFetch::findLostItems()
{
mBackgroundFetchActive = TRUE;
sFetchQueue.push_back(LLUUID::null);
gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL);
}
void LLInventoryModelBackgroundFetch::stopBackgroundFetch()
{
if (mBackgroundFetchActive)
{
mBackgroundFetchActive = FALSE;
gIdleCallbacks.deleteFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL);
mBulkFetchCount=0;
mMinTimeBetweenFetches=0.0f;
}
}
void LLInventoryModelBackgroundFetch::setAllFoldersFetched()
{
if (mInventoryFetchStarted &&
mLibraryFetchStarted)
{
mAllFoldersFetched = TRUE;
}
stopBackgroundFetch();
}
void LLInventoryModelBackgroundFetch::backgroundFetchCB(void *)
{
LLInventoryModelBackgroundFetch::instance().backgroundFetch();
}
void LLInventoryModelBackgroundFetch::backgroundFetch()
{
if (mBackgroundFetchActive && 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("WebFetchInventoryDescendents");
if (!url.empty())
{
bulkFetch(url);
return;
}
//DEPRECATED OLD CODE FOLLOWS.
// no more categories to fetch, stop fetch process
if (sFetchQueue.empty())
{
llinfos << "Inventory fetch completed" << llendl;
setAllFoldersFetched();
return;
}
F32 fast_fetch_time = lerp(mMinTimeBetweenFetches, mMaxTimeBetweenFetches, 0.1f);
F32 slow_fetch_time = lerp(mMinTimeBetweenFetches, mMaxTimeBetweenFetches, 0.5f);
if (mTimelyFetchPending && mFetchTimer.getElapsedTimeF32() > slow_fetch_time)
{
// double timeouts on failure
mMinTimeBetweenFetches = llmin(mMinTimeBetweenFetches * 2.f, 10.f);
mMaxTimeBetweenFetches = llmin(mMaxTimeBetweenFetches * 2.f, 120.f);
llinfos << "Inventory fetch times grown to (" << mMinTimeBetweenFetches << ", " << mMaxTimeBetweenFetches << ")" << llendl;
// fetch is no longer considered "timely" although we will wait for full time-out
mTimelyFetchPending = 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 (mFetchTimer.getElapsedTimeF32() > mMinTimeBetweenFetches &&
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())
{
mFetchTimer.reset();
mTimelyFetchPending = 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
LLInventoryModel::cat_array_t* categories;
LLInventoryModel::item_array_t* items;
gInventory.getDirectDescendentsOf(cat->getUUID(), categories, items);
for (LLInventoryModel::cat_array_t::const_iterator it = categories->begin();
it != categories->end();
++it)
{
sFetchQueue.push_back((*it)->getUUID());
}
// we received a response in less than the fast time
if (mTimelyFetchPending && mFetchTimer.getElapsedTimeF32() < fast_fetch_time)
{
// shrink timeouts based on success
mMinTimeBetweenFetches = llmax(mMinTimeBetweenFetches * 0.8f, 0.3f);
mMaxTimeBetweenFetches = llmax(mMaxTimeBetweenFetches * 0.8f, 10.f);
//llinfos << "Inventory fetch times shrunk to (" << mMinTimeBetweenFetches << ", " << mMaxTimeBetweenFetches << ")" << llendl;
}
mTimelyFetchPending = FALSE;
continue;
}
else if (mFetchTimer.getElapsedTimeF32() > mMaxTimeBetweenFetches)
{
// 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 (mNumFetchRetries++ < MAX_FETCH_RETRIES)
{
// push on back of queue
sFetchQueue.push_back(fetch_id);
}
mTimelyFetchPending = FALSE;
mFetchTimer.reset();
break;
}
// not enough time has elapsed to do a new fetch
break;
}
}
}
void LLInventoryModelBackgroundFetch::incrBulkFetch(S16 fetching)
{
mBulkFetchCount += fetching;
if (mBulkFetchCount < 0)
{
mBulkFetchCount = 0;
}
}
class LLInventoryModelFetchDescendentsResponder: public LLHTTPClient::Responder
{
public:
LLInventoryModelFetchDescendentsResponder(const LLSD& request_sd) : mRequestSD(request_sd) {};
//LLInventoryModelFetchDescendentsResponder() {};
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
void LLInventoryModelFetchDescendentsResponder::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)
{
const 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("fetchDescendents");
}
}
}
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 (LLInventoryModelBackgroundFetch::instance().inventoryFetchStarted() ||
LLInventoryModelBackgroundFetch::instance().libraryFetchStarted())
{
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);
cat->determineFolderType();
}
}
}
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.
llinfos << "Folder " << folder_sd["folder_id"].asString()
<< "Error: " << folder_sd["error"].asString() << llendl;
}
}
LLInventoryModelBackgroundFetch::instance().incrBulkFetch(-1);
if (LLInventoryModelBackgroundFetch::instance().isBulkFetchProcessingComplete())
{
llinfos << "Inventory fetch completed" << llendl;
LLInventoryModelBackgroundFetch::instance().setAllFoldersFetched();
}
gInventory.notifyObservers("fetchDescendents");
}
//If we get back an error (not found, etc...), handle it here
void LLInventoryModelFetchDescendentsResponder::error(U32 status, const std::string& reason)
{
llinfos << "LLInventoryModelFetchDescendentsResponder::error "
<< status << ": " << reason << llendl;
LLInventoryModelBackgroundFetch::instance().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 (LLInventoryModelBackgroundFetch::instance().isBulkFetchProcessingComplete())
{
LLInventoryModelBackgroundFetch::instance().setAllFoldersFetched();
}
}
gInventory.notifyObservers("fetchDescendents");
}
//static Bundle up a bunch of requests to send all at once.
void LLInventoryModelBackgroundFetch::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 (mMinTimeBetweenFetches < new_min_time)
{
mMinTimeBetweenFetches=new_min_time; //HACK! See above.
}
if (gDisconnected ||
(mBulkFetchCount > max_concurrent_fetches) ||
(mFetchTimer.getElapsedTimeF32() < mMinTimeBetweenFetches))
{
return; // just bail if we are disconnected.
}
U32 folder_count=0;
U32 max_batch_size=5;
U32 sort_order = gSavedSettings.getU32(LLInventoryPanel::DEFAULT_SORT_ORDER) & 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)
{
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;
if (ALEXANDRIA_LINDEN_ID == cat->getOwnerID())
body_lib["folders"].append(folder_sd);
else
body["folders"].append(folder_sd);
folder_count++;
}
if (mInventoryFetchStarted || mLibraryFetchStarted)
{ //Already have this folder but append child folders to list.
// add all children to queue
LLInventoryModel::cat_array_t* categories;
LLInventoryModel::item_array_t* items;
gInventory.getDirectDescendentsOf(cat->getUUID(), categories, items);
for (LLInventoryModel::cat_array_t::const_iterator it = categories->begin();
it != categories->end();
++it)
{
sFetchQueue.push_back((*it)->getUUID());
}
}
}
}
sFetchQueue.pop_front();
}
if (folder_count > 0)
{
mBulkFetchCount++;
if (body["folders"].size())
{
LLHTTPClient::post(url, body, new LLInventoryModelFetchDescendentsResponder(body),300.0);
}
if (body_lib["folders"].size())
{
std::string url_lib = gAgent.getRegion()->getCapability("FetchLibDescendents");
LLHTTPClient::post(url_lib, body_lib, new LLInventoryModelFetchDescendentsResponder(body_lib),300.0);
}
mFetchTimer.reset();
}
else if (isBulkFetchProcessingComplete())
{
setAllFoldersFetched();
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment