From bf49c0fcc472504db6e876620bedef56bc200da4 Mon Sep 17 00:00:00 2001 From: Loren Shih Date: Tue, 30 Mar 2010 15:38:16 -0400 Subject: Rename to remove camelcase from llinventorymodelbackground files. --- indra/newview/llinventorymodelbackgroundfetch.cpp | 603 ++++++++++++++++++++++ 1 file changed, 603 insertions(+) create mode 100644 indra/newview/llinventorymodelbackgroundfetch.cpp (limited to 'indra/newview/llinventorymodelbackgroundfetch.cpp') diff --git a/indra/newview/llinventorymodelbackgroundfetch.cpp b/indra/newview/llinventorymodelbackgroundfetch.cpp new file mode 100644 index 0000000000..72e5c0dd75 --- /dev/null +++ b/indra/newview/llinventorymodelbackgroundfetch.cpp @@ -0,0 +1,603 @@ +/** + * @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 sFetchQueue; +bool fetchQueueContainsNoDescendentsOf(const LLUUID& cat_id) +{ + for (std::deque::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 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 tcategory = new LLViewerInventoryCategory(owner_id); + + if (parent_id.isNull()) + { + LLPointer 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 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(); + } +} -- cgit v1.2.3 From 116c42750bd6186f77a0e5c15992fc0ce2752bdf Mon Sep 17 00:00:00 2001 From: Loren Shih Date: Tue, 30 Mar 2010 16:03:48 -0400 Subject: Rename to remove camelcase from llinventorymodelbackground files. --- indra/newview/llinventorymodelbackgroundfetch.cpp | 603 ---------------------- 1 file changed, 603 deletions(-) delete mode 100644 indra/newview/llinventorymodelbackgroundfetch.cpp (limited to 'indra/newview/llinventorymodelbackgroundfetch.cpp') diff --git a/indra/newview/llinventorymodelbackgroundfetch.cpp b/indra/newview/llinventorymodelbackgroundfetch.cpp deleted file mode 100644 index 72e5c0dd75..0000000000 --- a/indra/newview/llinventorymodelbackgroundfetch.cpp +++ /dev/null @@ -1,603 +0,0 @@ -/** - * @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 sFetchQueue; -bool fetchQueueContainsNoDescendentsOf(const LLUUID& cat_id) -{ - for (std::deque::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 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 tcategory = new LLViewerInventoryCategory(owner_id); - - if (parent_id.isNull()) - { - LLPointer 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 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(); - } -} -- cgit v1.2.3 From 094700f49926a1ffb0678bf83cd4670841b618f7 Mon Sep 17 00:00:00 2001 From: Loren Shih Date: Tue, 30 Mar 2010 16:05:16 -0400 Subject: Rename to remove camelcase from llinventorymodelbackground files. --- indra/newview/llinventorymodelbackgroundfetch.cpp | 603 ++++++++++++++++++++++ 1 file changed, 603 insertions(+) create mode 100644 indra/newview/llinventorymodelbackgroundfetch.cpp (limited to 'indra/newview/llinventorymodelbackgroundfetch.cpp') diff --git a/indra/newview/llinventorymodelbackgroundfetch.cpp b/indra/newview/llinventorymodelbackgroundfetch.cpp new file mode 100644 index 0000000000..72e5c0dd75 --- /dev/null +++ b/indra/newview/llinventorymodelbackgroundfetch.cpp @@ -0,0 +1,603 @@ +/** + * @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 sFetchQueue; +bool fetchQueueContainsNoDescendentsOf(const LLUUID& cat_id) +{ + for (std::deque::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 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 tcategory = new LLViewerInventoryCategory(owner_id); + + if (parent_id.isNull()) + { + LLPointer 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 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(); + } +} -- cgit v1.2.3 From 785d4c34b62b7ca76b292e0001c516ba8fa738bc Mon Sep 17 00:00:00 2001 From: Loren Shih Date: Tue, 6 Apr 2010 10:19:15 -0400 Subject: EXT-4151 : Immediately check if a fetchObserver filter is done, else add to observer list automatically Preliminary work to clean up naming conventions. --- indra/newview/llinventorymodelbackgroundfetch.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra/newview/llinventorymodelbackgroundfetch.cpp') diff --git a/indra/newview/llinventorymodelbackgroundfetch.cpp b/indra/newview/llinventorymodelbackgroundfetch.cpp index 72e5c0dd75..cfbc2c3e05 100644 --- a/indra/newview/llinventorymodelbackgroundfetch.cpp +++ b/indra/newview/llinventorymodelbackgroundfetch.cpp @@ -257,7 +257,7 @@ void LLInventoryModelBackgroundFetch::backgroundFetch() { // 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()) + if (cat->fetch()) { mFetchTimer.reset(); mTimelyFetchPending = TRUE; -- cgit v1.2.3 From a322dd0c2138bde56465633b943438ac378e6aab Mon Sep 17 00:00:00 2001 From: Loren Shih Date: Tue, 4 May 2010 15:29:12 -0400 Subject: EXT-7197 : Inventory caps is causing recursive inventory fetch on login Added code to support non-recursive inventory folder fetching for AIS. --- indra/newview/llinventorymodelbackgroundfetch.cpp | 120 ++++++++++++++-------- 1 file changed, 76 insertions(+), 44 deletions(-) (limited to 'indra/newview/llinventorymodelbackgroundfetch.cpp') diff --git a/indra/newview/llinventorymodelbackgroundfetch.cpp b/indra/newview/llinventorymodelbackgroundfetch.cpp index cfbc2c3e05..7d0cab0177 100644 --- a/indra/newview/llinventorymodelbackgroundfetch.cpp +++ b/indra/newview/llinventorymodelbackgroundfetch.cpp @@ -46,20 +46,17 @@ 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 sFetchQueue; -bool fetchQueueContainsNoDescendentsOf(const LLUUID& cat_id) +struct FetchQueueInfo { - for (std::deque::iterator it = sFetchQueue.begin(); - it != sFetchQueue.end(); ++it) + FetchQueueInfo(const LLUUID& id, BOOL recursive) : + mCatUUID(id), mRecursive(recursive) { - const LLUUID& fetch_id = *it; - if (gInventory.isObjectDescendentOf(fetch_id, cat_id)) - return false; } - return true; -} - + LLUUID mCatUUID; + BOOL mRecursive; +}; +typedef std::deque fetch_queue_t; +fetch_queue_t sFetchQueue; LLInventoryModelBackgroundFetch::LLInventoryModelBackgroundFetch() : mBackgroundFetchActive(FALSE), @@ -123,7 +120,7 @@ BOOL LLInventoryModelBackgroundFetch::backgroundFetchActive() return mBackgroundFetchActive; } -void LLInventoryModelBackgroundFetch::start(const LLUUID& cat_id) +void LLInventoryModelBackgroundFetch::start(const LLUUID& cat_id, BOOL recursive) { if (!mAllFoldersFetched) { @@ -133,22 +130,22 @@ void LLInventoryModelBackgroundFetch::start(const LLUUID& cat_id) if (!mInventoryFetchStarted) { mInventoryFetchStarted = TRUE; - sFetchQueue.push_back(gInventory.getRootFolderID()); + sFetchQueue.push_back(FetchQueueInfo(gInventory.getRootFolderID(), recursive)); gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL); } if (!mLibraryFetchStarted) { mLibraryFetchStarted = TRUE; - sFetchQueue.push_back(gInventory.getLibraryRootFolderID()); + sFetchQueue.push_back(FetchQueueInfo(gInventory.getLibraryRootFolderID(), recursive)); gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL); } } else { // specific folder requests go to front of queue - if (sFetchQueue.empty() || sFetchQueue.front() != cat_id) + if (sFetchQueue.empty() || sFetchQueue.front().mCatUUID != cat_id) { - sFetchQueue.push_front(cat_id); + sFetchQueue.push_front(FetchQueueInfo(cat_id, recursive)); gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL); } if (cat_id == gInventory.getLibraryRootFolderID()) @@ -166,7 +163,7 @@ void LLInventoryModelBackgroundFetch::start(const LLUUID& cat_id) void LLInventoryModelBackgroundFetch::findLostItems() { mBackgroundFetchActive = TRUE; - sFetchQueue.push_back(LLUUID::null); + sFetchQueue.push_back(FetchQueueInfo(LLUUID::null, TRUE)); gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL); } @@ -243,7 +240,8 @@ void LLInventoryModelBackgroundFetch::backgroundFetch() break; } - LLViewerInventoryCategory* cat = gInventory.getCategory(sFetchQueue.front()); + const FetchQueueInfo info = sFetchQueue.front(); + LLViewerInventoryCategory* cat = gInventory.getCategory(info.mCatUUID); // category has been deleted, remove from queue. if (!cat) @@ -271,7 +269,7 @@ void LLInventoryModelBackgroundFetch::backgroundFetch() } } // do I have all my children? - else if (gInventory.isCategoryComplete(sFetchQueue.front())) + else if (gInventory.isCategoryComplete(info.mCatUUID)) { // finished with this category, remove from queue sFetchQueue.pop_front(); @@ -284,7 +282,7 @@ void LLInventoryModelBackgroundFetch::backgroundFetch() it != categories->end(); ++it) { - sFetchQueue.push_back((*it)->getUUID()); + sFetchQueue.push_back(FetchQueueInfo((*it)->getUUID(),info.mRecursive)); } // we received a response in less than the fast time @@ -303,13 +301,12 @@ void LLInventoryModelBackgroundFetch::backgroundFetch() { // 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); + sFetchQueue.push_back(info); } mTimelyFetchPending = FALSE; mFetchTimer.reset(); @@ -334,15 +331,19 @@ void LLInventoryModelBackgroundFetch::incrBulkFetch(S16 fetching) 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 folder_ref_t; - protected: - LLSD mRequestSD; +public: + LLInventoryModelFetchDescendentsResponder(const LLSD& request_sd, uuid_vec_t recursive_cats) : + mRequestSD(request_sd), + mRecursiveCatUUIDs(recursive_cats) + {}; + //LLInventoryModelFetchDescendentsResponder() {}; + void result(const LLSD& content); + void error(U32 status, const std::string& reason); +protected: + BOOL getIsRecursive(const LLUUID& cat_id) const; +private: + LLSD mRequestSD; + uuid_vec_t mRecursiveCatUUIDs; // Hack for storing away which cat fetches are recursive. }; //If we get back a normal response, handle it here @@ -412,11 +413,12 @@ void LLInventoryModelFetchDescendentsResponder::result(const LLSD& content) { LLSD category = *category_it; tcategory->fromLLSD(category); - - if (LLInventoryModelBackgroundFetch::instance().inventoryFetchStarted() || - LLInventoryModelBackgroundFetch::instance().libraryFetchStarted()) + + const BOOL recursive = getIsRecursive(tcategory->getUUID()); + + if (recursive) { - sFetchQueue.push_back(tcategory->getUUID()); + sFetchQueue.push_back(FetchQueueInfo(tcategory->getUUID(), recursive)); } else if ( !gInventory.isCategoryComplete(tcategory->getUUID()) ) { @@ -488,7 +490,8 @@ void LLInventoryModelFetchDescendentsResponder::error(U32 status, const std::str { LLSD folder_sd = *folder_it; LLUUID folder_id = folder_sd["folder_id"]; - sFetchQueue.push_front(folder_id); + const BOOL recursive = getIsRecursive(folder_id); + sFetchQueue.push_front(FetchQueueInfo(folder_id, recursive)); } } else @@ -501,6 +504,11 @@ void LLInventoryModelFetchDescendentsResponder::error(U32 status, const std::str gInventory.notifyObservers("fetchDescendents"); } +BOOL LLInventoryModelFetchDescendentsResponder::getIsRecursive(const LLUUID& cat_id) const +{ + return (std::find(mRecursiveCatUUIDs.begin(),mRecursiveCatUUIDs.end(), cat_id) != mRecursiveCatUUIDs.end()); +} + //static Bundle up a bunch of requests to send all at once. void LLInventoryModelBackgroundFetch::bulkFetch(std::string url) { @@ -528,11 +536,15 @@ void LLInventoryModelBackgroundFetch::bulkFetch(std::string url) U32 sort_order = gSavedSettings.getU32(LLInventoryPanel::DEFAULT_SORT_ORDER) & 0x1; + uuid_vec_t recursive_cats; + LLSD body; LLSD body_lib; while (!(sFetchQueue.empty()) && (folder_count < max_batch_size)) { - if (sFetchQueue.front().isNull()) //DEV-17797 + const FetchQueueInfo& fetch_info = sFetchQueue.front(); + const LLUUID &cat_id = fetch_info.mCatUUID; + if (cat_id.isNull()) //DEV-17797 { LLSD folder_sd; folder_sd["folder_id"] = LLUUID::null.asString(); @@ -545,7 +557,7 @@ void LLInventoryModelBackgroundFetch::bulkFetch(std::string url) } else { - LLViewerInventoryCategory* cat = gInventory.getCategory(sFetchQueue.front()); + const LLViewerInventoryCategory* cat = gInventory.getCategory(cat_id); if (cat) { @@ -564,9 +576,9 @@ void LLInventoryModelBackgroundFetch::bulkFetch(std::string url) 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 + // May already have this folder, but append child folders to list. + if (fetch_info.mRecursive) + { LLInventoryModel::cat_array_t* categories; LLInventoryModel::item_array_t* items; gInventory.getDirectDescendentsOf(cat->getUUID(), categories, items); @@ -574,11 +586,14 @@ void LLInventoryModelBackgroundFetch::bulkFetch(std::string url) it != categories->end(); ++it) { - sFetchQueue.push_back((*it)->getUUID()); + sFetchQueue.push_back(FetchQueueInfo((*it)->getUUID(), fetch_info.mRecursive)); } } } } + if (fetch_info.mRecursive) + recursive_cats.push_back(cat_id); + sFetchQueue.pop_front(); } @@ -587,12 +602,15 @@ void LLInventoryModelBackgroundFetch::bulkFetch(std::string url) mBulkFetchCount++; if (body["folders"].size()) { - LLHTTPClient::post(url, body, new LLInventoryModelFetchDescendentsResponder(body),300.0); + LLInventoryModelFetchDescendentsResponder *fetcher = new LLInventoryModelFetchDescendentsResponder(body, recursive_cats); + LLHTTPClient::post(url, body, fetcher, 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); + + LLInventoryModelFetchDescendentsResponder *fetcher = new LLInventoryModelFetchDescendentsResponder(body_lib, recursive_cats); + LLHTTPClient::post(url_lib, body_lib, fetcher, 300.0); } mFetchTimer.reset(); } @@ -601,3 +619,17 @@ void LLInventoryModelBackgroundFetch::bulkFetch(std::string url) setAllFoldersFetched(); } } + +bool LLInventoryModelBackgroundFetch::fetchQueueContainsNoDescendentsOf(const LLUUID& cat_id) const +{ + for (fetch_queue_t::const_iterator it = sFetchQueue.begin(); + it != sFetchQueue.end(); ++it) + { + const LLUUID& fetch_id = (*it).mCatUUID; + if (gInventory.isObjectDescendentOf(fetch_id, cat_id)) + return false; + } + return true; +} + + -- cgit v1.2.3 From 9ccb83520758ff8967ad7e32594074266504d4c2 Mon Sep 17 00:00:00 2001 From: Loren Shih Date: Tue, 4 May 2010 16:53:18 -0400 Subject: DEV-49557 : FIXED : Attachments can show up hanging in space Fix for logic about when all folders have been fetched. Some infrastructure cleanup. --- indra/newview/llinventorymodelbackgroundfetch.cpp | 102 ++++++++++------------ 1 file changed, 47 insertions(+), 55 deletions(-) (limited to 'indra/newview/llinventorymodelbackgroundfetch.cpp') diff --git a/indra/newview/llinventorymodelbackgroundfetch.cpp b/indra/newview/llinventorymodelbackgroundfetch.cpp index 7d0cab0177..0ff6ab2644 100644 --- a/indra/newview/llinventorymodelbackgroundfetch.cpp +++ b/indra/newview/llinventorymodelbackgroundfetch.cpp @@ -46,23 +46,11 @@ const F32 MAX_TIME_FOR_SINGLE_FETCH = 10.f; const S32 MAX_FETCH_RETRIES = 10; -struct FetchQueueInfo -{ - FetchQueueInfo(const LLUUID& id, BOOL recursive) : - mCatUUID(id), mRecursive(recursive) - { - } - LLUUID mCatUUID; - BOOL mRecursive; -}; -typedef std::deque fetch_queue_t; -fetch_queue_t sFetchQueue; - LLInventoryModelBackgroundFetch::LLInventoryModelBackgroundFetch() : mBackgroundFetchActive(FALSE), mAllFoldersFetched(FALSE), - mInventoryFetchStarted(FALSE), - mLibraryFetchStarted(FALSE), + mRecursiveInventoryFetchStarted(FALSE), + mRecursiveLibraryFetchStarted(FALSE), mNumFetchRetries(0), mMinTimeBetweenFetches(0.3f), mMaxTimeBetweenFetches(10.f), @@ -77,12 +65,12 @@ LLInventoryModelBackgroundFetch::~LLInventoryModelBackgroundFetch() bool LLInventoryModelBackgroundFetch::isBulkFetchProcessingComplete() { - return sFetchQueue.empty() && mBulkFetchCount<=0; + return mFetchQueue.empty() && mBulkFetchCount<=0; } bool LLInventoryModelBackgroundFetch::libraryFetchStarted() { - return mLibraryFetchStarted; + return mRecursiveLibraryFetchStarted; } bool LLInventoryModelBackgroundFetch::libraryFetchCompleted() @@ -97,7 +85,7 @@ bool LLInventoryModelBackgroundFetch::libraryFetchInProgress() bool LLInventoryModelBackgroundFetch::inventoryFetchStarted() { - return mInventoryFetchStarted; + return mRecursiveInventoryFetchStarted; } bool LLInventoryModelBackgroundFetch::inventoryFetchCompleted() @@ -127,34 +115,34 @@ void LLInventoryModelBackgroundFetch::start(const LLUUID& cat_id, BOOL recursive mBackgroundFetchActive = TRUE; if (cat_id.isNull()) { - if (!mInventoryFetchStarted) + if (!mRecursiveInventoryFetchStarted) { - mInventoryFetchStarted = TRUE; - sFetchQueue.push_back(FetchQueueInfo(gInventory.getRootFolderID(), recursive)); + mRecursiveInventoryFetchStarted |= recursive; + mFetchQueue.push_back(FetchQueueInfo(gInventory.getRootFolderID(), recursive)); gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL); } - if (!mLibraryFetchStarted) + if (!mRecursiveLibraryFetchStarted) { - mLibraryFetchStarted = TRUE; - sFetchQueue.push_back(FetchQueueInfo(gInventory.getLibraryRootFolderID(), recursive)); + mRecursiveLibraryFetchStarted |= recursive; + mFetchQueue.push_back(FetchQueueInfo(gInventory.getLibraryRootFolderID(), recursive)); gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL); } } else { // specific folder requests go to front of queue - if (sFetchQueue.empty() || sFetchQueue.front().mCatUUID != cat_id) + if (mFetchQueue.empty() || mFetchQueue.front().mCatUUID != cat_id) { - sFetchQueue.push_front(FetchQueueInfo(cat_id, recursive)); + mFetchQueue.push_front(FetchQueueInfo(cat_id, recursive)); gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL); } if (cat_id == gInventory.getLibraryRootFolderID()) { - mLibraryFetchStarted = TRUE; + mRecursiveLibraryFetchStarted |= recursive; } if (cat_id == gInventory.getRootFolderID()) { - mInventoryFetchStarted = TRUE; + mRecursiveInventoryFetchStarted |= recursive; } } } @@ -163,7 +151,7 @@ void LLInventoryModelBackgroundFetch::start(const LLUUID& cat_id, BOOL recursive void LLInventoryModelBackgroundFetch::findLostItems() { mBackgroundFetchActive = TRUE; - sFetchQueue.push_back(FetchQueueInfo(LLUUID::null, TRUE)); + mFetchQueue.push_back(FetchQueueInfo(LLUUID::null, TRUE)); gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL); } @@ -180,8 +168,8 @@ void LLInventoryModelBackgroundFetch::stopBackgroundFetch() void LLInventoryModelBackgroundFetch::setAllFoldersFetched() { - if (mInventoryFetchStarted && - mLibraryFetchStarted) + if (mRecursiveInventoryFetchStarted && + mRecursiveLibraryFetchStarted) { mAllFoldersFetched = TRUE; } @@ -207,7 +195,7 @@ void LLInventoryModelBackgroundFetch::backgroundFetch() //DEPRECATED OLD CODE FOLLOWS. // no more categories to fetch, stop fetch process - if (sFetchQueue.empty()) + if (mFetchQueue.empty()) { llinfos << "Inventory fetch completed" << llendl; @@ -229,7 +217,7 @@ void LLInventoryModelBackgroundFetch::backgroundFetch() while(1) { - if (sFetchQueue.empty()) + if (mFetchQueue.empty()) { break; } @@ -240,13 +228,13 @@ void LLInventoryModelBackgroundFetch::backgroundFetch() break; } - const FetchQueueInfo info = sFetchQueue.front(); + const FetchQueueInfo info = mFetchQueue.front(); LLViewerInventoryCategory* cat = gInventory.getCategory(info.mCatUUID); // category has been deleted, remove from queue. if (!cat) { - sFetchQueue.pop_front(); + mFetchQueue.pop_front(); continue; } @@ -272,7 +260,7 @@ void LLInventoryModelBackgroundFetch::backgroundFetch() else if (gInventory.isCategoryComplete(info.mCatUUID)) { // finished with this category, remove from queue - sFetchQueue.pop_front(); + mFetchQueue.pop_front(); // add all children to queue LLInventoryModel::cat_array_t* categories; @@ -282,7 +270,7 @@ void LLInventoryModelBackgroundFetch::backgroundFetch() it != categories->end(); ++it) { - sFetchQueue.push_back(FetchQueueInfo((*it)->getUUID(),info.mRecursive)); + mFetchQueue.push_back(FetchQueueInfo((*it)->getUUID(),info.mRecursive)); } // we received a response in less than the fast time @@ -301,12 +289,12 @@ void LLInventoryModelBackgroundFetch::backgroundFetch() { // received first packet, but our num descendants does not match db's num descendants // so try again later - sFetchQueue.pop_front(); + mFetchQueue.pop_front(); if (mNumFetchRetries++ < MAX_FETCH_RETRIES) { // push on back of queue - sFetchQueue.push_back(info); + mFetchQueue.push_back(info); } mTimelyFetchPending = FALSE; mFetchTimer.reset(); @@ -347,8 +335,9 @@ private: }; //If we get back a normal response, handle it here -void LLInventoryModelFetchDescendentsResponder::result(const LLSD& content) +void LLInventoryModelFetchDescendentsResponder::result(const LLSD& content) { + LLInventoryModelBackgroundFetch *fetcher = LLInventoryModelBackgroundFetch::getInstance(); if (content.has("folders")) { @@ -418,7 +407,7 @@ void LLInventoryModelFetchDescendentsResponder::result(const LLSD& content) if (recursive) { - sFetchQueue.push_back(FetchQueueInfo(tcategory->getUUID(), recursive)); + fetcher->mFetchQueue.push_back(LLInventoryModelBackgroundFetch::FetchQueueInfo(tcategory->getUUID(), recursive)); } else if ( !gInventory.isCategoryComplete(tcategory->getUUID()) ) { @@ -463,12 +452,12 @@ void LLInventoryModelFetchDescendentsResponder::result(const LLSD& content) } } - LLInventoryModelBackgroundFetch::instance().incrBulkFetch(-1); + fetcher->incrBulkFetch(-1); - if (LLInventoryModelBackgroundFetch::instance().isBulkFetchProcessingComplete()) + if (fetcher->isBulkFetchProcessingComplete()) { llinfos << "Inventory fetch completed" << llendl; - LLInventoryModelBackgroundFetch::instance().setAllFoldersFetched(); + fetcher->setAllFoldersFetched(); } gInventory.notifyObservers("fetchDescendents"); @@ -477,12 +466,14 @@ void LLInventoryModelFetchDescendentsResponder::result(const LLSD& content) //If we get back an error (not found, etc...), handle it here void LLInventoryModelFetchDescendentsResponder::error(U32 status, const std::string& reason) { + LLInventoryModelBackgroundFetch *fetcher = LLInventoryModelBackgroundFetch::getInstance(); + llinfos << "LLInventoryModelFetchDescendentsResponder::error " << status << ": " << reason << llendl; - LLInventoryModelBackgroundFetch::instance().incrBulkFetch(-1); + fetcher->incrBulkFetch(-1); - if (status==499) //timed out. Let's be awesome! + if (status==499) // Timed out. { for(LLSD::array_const_iterator folder_it = mRequestSD["folders"].beginArray(); folder_it != mRequestSD["folders"].endArray(); @@ -491,14 +482,14 @@ void LLInventoryModelFetchDescendentsResponder::error(U32 status, const std::str LLSD folder_sd = *folder_it; LLUUID folder_id = folder_sd["folder_id"]; const BOOL recursive = getIsRecursive(folder_id); - sFetchQueue.push_front(FetchQueueInfo(folder_id, recursive)); + fetcher->mFetchQueue.push_front(LLInventoryModelBackgroundFetch::FetchQueueInfo(folder_id, recursive)); } } else { - if (LLInventoryModelBackgroundFetch::instance().isBulkFetchProcessingComplete()) + if (fetcher->isBulkFetchProcessingComplete()) { - LLInventoryModelBackgroundFetch::instance().setAllFoldersFetched(); + fetcher->setAllFoldersFetched(); } } gInventory.notifyObservers("fetchDescendents"); @@ -513,7 +504,7 @@ BOOL LLInventoryModelFetchDescendentsResponder::getIsRecursive(const LLUUID& cat 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 + //If there are items in mFetchQueue, 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. @@ -540,9 +531,10 @@ void LLInventoryModelBackgroundFetch::bulkFetch(std::string url) LLSD body; LLSD body_lib; - while (!(sFetchQueue.empty()) && (folder_count < max_batch_size)) + + while (!(mFetchQueue.empty()) && (folder_count < max_batch_size)) { - const FetchQueueInfo& fetch_info = sFetchQueue.front(); + const FetchQueueInfo& fetch_info = mFetchQueue.front(); const LLUUID &cat_id = fetch_info.mCatUUID; if (cat_id.isNull()) //DEV-17797 { @@ -586,7 +578,7 @@ void LLInventoryModelBackgroundFetch::bulkFetch(std::string url) it != categories->end(); ++it) { - sFetchQueue.push_back(FetchQueueInfo((*it)->getUUID(), fetch_info.mRecursive)); + mFetchQueue.push_back(FetchQueueInfo((*it)->getUUID(), fetch_info.mRecursive)); } } } @@ -594,7 +586,7 @@ void LLInventoryModelBackgroundFetch::bulkFetch(std::string url) if (fetch_info.mRecursive) recursive_cats.push_back(cat_id); - sFetchQueue.pop_front(); + mFetchQueue.pop_front(); } if (folder_count > 0) @@ -622,8 +614,8 @@ void LLInventoryModelBackgroundFetch::bulkFetch(std::string url) bool LLInventoryModelBackgroundFetch::fetchQueueContainsNoDescendentsOf(const LLUUID& cat_id) const { - for (fetch_queue_t::const_iterator it = sFetchQueue.begin(); - it != sFetchQueue.end(); ++it) + for (fetch_queue_t::const_iterator it = mFetchQueue.begin(); + it != mFetchQueue.end(); ++it) { const LLUUID& fetch_id = (*it).mCatUUID; if (gInventory.isObjectDescendentOf(fetch_id, cat_id)) -- cgit v1.2.3