summaryrefslogtreecommitdiff
path: root/indra/newview/llinventorymodelbackgroundfetch.cpp
diff options
context:
space:
mode:
authorMonty Brandenberg <monty@lindenlab.com>2014-08-22 18:04:27 -0400
committerMonty Brandenberg <monty@lindenlab.com>2014-08-22 18:04:27 -0400
commit85cba58ad473ed28efda7f645af20d56229e8637 (patch)
treea797df23a9c373eabf113356186991ab30e76648 /indra/newview/llinventorymodelbackgroundfetch.cpp
parente79a88c8ccfadcd260892000d4dec2ae921b26de (diff)
Add an HTTP policy class for inventory operations using four (4)
connections. Convert background and foreground fetches, both items and folders/inventory and library, to use new HTTP. Non-fetch inventory operations continue to use LLHTTPClient (at least for now). Error handling and retry on fetches wasn't 100% previously and that's still the case. I'll rip through this again to clean that up. Cleaned up logging in much of the inventory code with consistent labels on logging events and correct macros (removed deprecation warnings). This started as an attempt to get libcurl to do pipelining on POSTs and PUTs. Discovered that this is going to be very difficult to support in general in libcurl. May look at that again in the future.
Diffstat (limited to 'indra/newview/llinventorymodelbackgroundfetch.cpp')
-rwxr-xr-xindra/newview/llinventorymodelbackgroundfetch.cpp740
1 files changed, 450 insertions, 290 deletions
diff --git a/indra/newview/llinventorymodelbackgroundfetch.cpp b/indra/newview/llinventorymodelbackgroundfetch.cpp
index 2de37b0790..443c54df42 100755
--- a/indra/newview/llinventorymodelbackgroundfetch.cpp
+++ b/indra/newview/llinventorymodelbackgroundfetch.cpp
@@ -4,7 +4,7 @@
*
* $LicenseInfo:firstyear=2002&license=viewerlgpl$
* Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
+ * Copyright (C) 2014, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -37,31 +37,113 @@
#include "llviewermessage.h"
#include "llviewerregion.h"
#include "llviewerwindow.h"
+#include "llhttpconstants.h"
+#include "bufferarray.h"
+#include "bufferstream.h"
+#include "llsdserialize.h"
+
+namespace
+{
+
+// Http request handler class for single inventory item requests.
+//
+// We'll use a handler-per-request pattern here rather than
+// a shared handler. Mainly convenient as this was converted
+// from a Responder class model.
+//
+class BGItemHttpHandler : public LLInventoryModel::FetchItemHttpHandler
+{
+ LOG_CLASS(BGItemHttpHandler);
+
+public:
+ BGItemHttpHandler(const LLSD & request_sd)
+ : LLInventoryModel::FetchItemHttpHandler(request_sd)
+ {
+ LLInventoryModelBackgroundFetch::instance().incrFetchCount(1);
+ }
+
+ virtual ~BGItemHttpHandler()
+ {
+ LLInventoryModelBackgroundFetch::instance().incrFetchCount(-1);
+ }
+
+protected:
+ BGItemHttpHandler(const BGItemHttpHandler &); // Not defined
+ void operator=(const BGItemHttpHandler &); // Not defined
+};
+
+
+// Http request handler class for folders.
+class BGFolderHttpHandler : public LLCore::HttpHandler
+{
+ LOG_CLASS(BGFolderHttpHandler);
+
+public:
+ BGFolderHttpHandler(const LLSD & request_sd, const uuid_vec_t & recursive_cats)
+ : LLCore::HttpHandler(),
+ mRequestSD(request_sd),
+ mRecursiveCatUUIDs(recursive_cats)
+ {
+ LLInventoryModelBackgroundFetch::instance().incrFetchCount(1);
+ }
+
+ virtual ~BGFolderHttpHandler()
+ {
+ LLInventoryModelBackgroundFetch::instance().incrFetchCount(-1);
+ }
+
+protected:
+ BGFolderHttpHandler(const BGFolderHttpHandler &); // Not defined
+ void operator=(const BGFolderHttpHandler &); // Not defined
+
+public:
+ virtual void onCompleted(LLCore::HttpHandle handle, LLCore::HttpResponse * response);
+
+ bool getIsRecursive(const LLUUID & cat_id) const;
+
+private:
+ void processData(LLSD & body, LLCore::HttpResponse * response);
+ void processFailure(LLCore::HttpStatus status, LLCore::HttpResponse * response);
+ void processFailure(const char * const reason, LLCore::HttpResponse * response);
+
+private:
+ LLSD mRequestSD;
+ const uuid_vec_t mRecursiveCatUUIDs; // hack for storing away which cat fetches are recursive
+};
+
-const F32 MAX_TIME_FOR_SINGLE_FETCH = 10.f;
const S32 MAX_FETCH_RETRIES = 10;
-LLInventoryModelBackgroundFetch::LLInventoryModelBackgroundFetch() :
+const char * const LOG_INV("Inventory");
+
+std::string dumpResponse()
+{
+ return std::string("ADD SOMETHING MEANINGFUL HERE");
+}
+
+
+} // end of namespace anonymous
+
+
+LLInventoryModelBackgroundFetch::LLInventoryModelBackgroundFetch():
mBackgroundFetchActive(FALSE),
mFolderFetchActive(false),
+ mFetchCount(0),
mAllFoldersFetched(FALSE),
mRecursiveInventoryFetchStarted(FALSE),
mRecursiveLibraryFetchStarted(FALSE),
mNumFetchRetries(0),
mMinTimeBetweenFetches(0.3f),
mMaxTimeBetweenFetches(10.f),
- mTimelyFetchPending(FALSE),
- mFetchCount(0)
-{
-}
+ mTimelyFetchPending(FALSE)
+{}
LLInventoryModelBackgroundFetch::~LLInventoryModelBackgroundFetch()
-{
-}
+{}
bool LLInventoryModelBackgroundFetch::isBulkFetchProcessingComplete() const
{
- return mFetchQueue.empty() && mFetchCount<=0;
+ return mFetchQueue.empty() && mFetchCount <= 0;
}
bool LLInventoryModelBackgroundFetch::libraryFetchStarted() const
@@ -91,7 +173,7 @@ bool LLInventoryModelBackgroundFetch::inventoryFetchCompleted() const
bool LLInventoryModelBackgroundFetch::inventoryFetchInProgress() const
{
- return inventoryFetchStarted() && !inventoryFetchCompleted();
+ return inventoryFetchStarted() && ! inventoryFetchCompleted();
}
bool LLInventoryModelBackgroundFetch::isEverythingFetched() const
@@ -104,24 +186,36 @@ BOOL LLInventoryModelBackgroundFetch::folderFetchActive() const
return mFolderFetchActive;
}
+void LLInventoryModelBackgroundFetch::addRequestAtFront(const LLUUID & id, BOOL recursive, bool is_category)
+{
+ mFetchQueue.push_front(FetchQueueInfo(id, recursive, is_category));
+}
+
+void LLInventoryModelBackgroundFetch::addRequestAtBack(const LLUUID & id, BOOL recursive, bool is_category)
+{
+ mFetchQueue.push_back(FetchQueueInfo(id, recursive, is_category));
+}
+
void LLInventoryModelBackgroundFetch::start(const LLUUID& id, BOOL recursive)
{
- LLViewerInventoryCategory* cat = gInventory.getCategory(id);
- if (cat || (id.isNull() && !isEverythingFetched()))
- { // it's a folder, do a bulk fetch
- LL_DEBUGS("InventoryFetch") << "Start fetching category: " << id << ", recursive: " << recursive << LL_ENDL;
+ LLViewerInventoryCategory * cat(gInventory.getCategory(id));
+
+ if (cat || (id.isNull() && ! isEverythingFetched()))
+ {
+ // it's a folder, do a bulk fetch
+ LL_DEBUGS(LOG_INV) << "Start fetching category: " << id << ", recursive: " << recursive << LL_ENDL;
mBackgroundFetchActive = TRUE;
mFolderFetchActive = true;
if (id.isNull())
{
- if (!mRecursiveInventoryFetchStarted)
+ if (! mRecursiveInventoryFetchStarted)
{
mRecursiveInventoryFetchStarted |= recursive;
mFetchQueue.push_back(FetchQueueInfo(gInventory.getRootFolderID(), recursive));
gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL);
}
- if (!mRecursiveLibraryFetchStarted)
+ if (! mRecursiveLibraryFetchStarted)
{
mRecursiveLibraryFetchStarted |= recursive;
mFetchQueue.push_back(FetchQueueInfo(gInventory.getLibraryRootFolderID(), recursive));
@@ -146,9 +240,9 @@ void LLInventoryModelBackgroundFetch::start(const LLUUID& id, BOOL recursive)
}
}
}
- else if (LLViewerInventoryItem* itemp = gInventory.getItem(id))
+ else if (LLViewerInventoryItem * itemp = gInventory.getItem(id))
{
- if (!itemp->mIsComplete && (mFetchQueue.empty() || mFetchQueue.front().mUUID != id))
+ if (! itemp->mIsComplete && (mFetchQueue.empty() || mFetchQueue.front().mUUID != id))
{
mBackgroundFetchActive = TRUE;
@@ -172,7 +266,7 @@ void LLInventoryModelBackgroundFetch::setAllFoldersFetched()
mRecursiveLibraryFetchStarted)
{
mAllFoldersFetched = TRUE;
- //LL_INFOS() << "All folders fetched, validating" << LL_ENDL;
+ //LL_INFOS(LOG_INV) << "All folders fetched, validating" << LL_ENDL;
//gInventory.validate();
}
mFolderFetchActive = false;
@@ -203,7 +297,7 @@ void LLInventoryModelBackgroundFetch::backgroundFetch()
// No more categories to fetch, stop fetch process.
if (mFetchQueue.empty())
{
- LL_INFOS() << "Inventory fetch completed" << LL_ENDL;
+ LL_INFOS(LOG_INV) << "Inventory fetch completed" << LL_ENDL;
setAllFoldersFetched();
mBackgroundFetchActive = false;
@@ -219,7 +313,7 @@ void LLInventoryModelBackgroundFetch::backgroundFetch()
// Double timeouts on failure.
mMinTimeBetweenFetches = llmin(mMinTimeBetweenFetches * 2.f, 10.f);
mMaxTimeBetweenFetches = llmin(mMaxTimeBetweenFetches * 2.f, 120.f);
- LL_DEBUGS() << "Inventory fetch times grown to (" << mMinTimeBetweenFetches << ", " << mMaxTimeBetweenFetches << ")" << LL_ENDL;
+ LL_DEBUGS(LOG_INV) << "Inventory fetch times grown to (" << mMinTimeBetweenFetches << ", " << mMaxTimeBetweenFetches << ")" << LL_ENDL;
// fetch is no longer considered "timely" although we will wait for full time-out.
mTimelyFetchPending = FALSE;
}
@@ -231,7 +325,7 @@ void LLInventoryModelBackgroundFetch::backgroundFetch()
break;
}
- if(gDisconnected)
+ if (gDisconnected)
{
// Just bail if we are disconnected.
break;
@@ -292,7 +386,7 @@ void LLInventoryModelBackgroundFetch::backgroundFetch()
// Shrink timeouts based on success.
mMinTimeBetweenFetches = llmax(mMinTimeBetweenFetches * 0.8f, 0.3f);
mMaxTimeBetweenFetches = llmax(mMaxTimeBetweenFetches * 0.8f, 10.f);
- LL_DEBUGS() << "Inventory fetch times shrunk to (" << mMinTimeBetweenFetches << ", " << mMaxTimeBetweenFetches << ")" << LL_ENDL;
+ LL_DEBUGS(LOG_INV) << "Inventory fetch times shrunk to (" << mMinTimeBetweenFetches << ", " << mMaxTimeBetweenFetches << ")" << LL_ENDL;
}
mTimelyFetchPending = FALSE;
@@ -355,257 +449,53 @@ void LLInventoryModelBackgroundFetch::backgroundFetch()
}
}
-void LLInventoryModelBackgroundFetch::incrFetchCount(S16 fetching)
+void LLInventoryModelBackgroundFetch::incrFetchCount(S32 fetching)
{
mFetchCount += fetching;
if (mFetchCount < 0)
{
+ LL_WARNS_ONCE(LOG_INV) << "Inventory fetch count fell below zero (0)." << LL_ENDL;
mFetchCount = 0;
}
}
-class LLInventoryModelFetchItemResponder : public LLInventoryModel::fetchInventoryResponder
-{
- LOG_CLASS(LLInventoryModelFetchItemResponder);
-public:
- LLInventoryModelFetchItemResponder(const LLSD& request_sd) :
- LLInventoryModel::fetchInventoryResponder(request_sd)
- {
- LLInventoryModelBackgroundFetch::instance().incrFetchCount(1);
- }
-private:
- /* virtual */ void httpCompleted()
- {
- LLInventoryModelBackgroundFetch::instance().incrFetchCount(-1);
- LLInventoryModel::fetchInventoryResponder::httpCompleted();
- }
-};
-
-class LLInventoryModelFetchDescendentsResponder: public LLHTTPClient::Responder
-{
- LOG_CLASS(LLInventoryModelFetchDescendentsResponder);
-public:
- LLInventoryModelFetchDescendentsResponder(const LLSD& request_sd, uuid_vec_t recursive_cats) :
- mRequestSD(request_sd),
- mRecursiveCatUUIDs(recursive_cats)
- {
- LLInventoryModelBackgroundFetch::instance().incrFetchCount(1);
- }
- //LLInventoryModelFetchDescendentsResponder() {};
-private:
- /* virtual */ void httpCompleted()
- {
- LLInventoryModelBackgroundFetch::instance().incrFetchCount(-1);
- LLHTTPClient::Responder::httpCompleted();
- }
- /* virtual */ void httpSuccess();
- /* virtual */ void httpFailure();
-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.
-void LLInventoryModelFetchDescendentsResponder::httpSuccess()
+// Bundle up a bunch of requests to send all at once.
+void LLInventoryModelBackgroundFetch::bulkFetch()
{
- const LLSD& content = getContent();
- if (!content.isMap())
+ //Background fetch is called from gIdleCallbacks in a loop until background fetch is stopped.
+ //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.
+ LLViewerRegion * region(gAgent.getRegion());
+ if (! region || gDisconnected)
{
- failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content);
return;
}
- LLInventoryModelBackgroundFetch *fetcher = LLInventoryModelBackgroundFetch::getInstance();
- 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.
- //{
- // LL_WARNS() << "Got a UpdateInventoryItem for the wrong agent."
- // << LL_ENDL;
- // 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();
-
- }
- }
- }
-
- 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);
-
- const BOOL recursive = getIsRecursive(tcategory->getUUID());
-
- if (recursive)
- {
- fetcher->mFetchQueue.push_back(LLInventoryModelBackgroundFetch::FetchQueueInfo(tcategory->getUUID(), recursive));
- }
- 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)
- {
- // *TODO: Stop copying data
- LLSD folder_sd = *folder_it;
-
- // These folders failed on the dataserver. We probably don't want to retry them.
- LL_WARNS() << "Folder " << folder_sd["folder_id"].asString()
- << "Error: " << folder_sd["error"].asString() << LL_ENDL;
- }
- }
+ static const S32 max_concurrent_fetches(12); // Outstanding requests, not connections
+ static const F32 new_min_time(0.5f); // *HACK: Clean this up when old code goes away entirely.
+ static const U32 max_batch_size(10);
- if (fetcher->isBulkFetchProcessingComplete())
+ if (mMinTimeBetweenFetches < new_min_time)
{
- LL_INFOS() << "Inventory fetch completed" << LL_ENDL;
- fetcher->setAllFoldersFetched();
+ mMinTimeBetweenFetches = new_min_time; // *HACK: See above.
}
-
- gInventory.notifyObservers();
-}
-
-// If we get back an error (not found, etc...), handle it here.
-void LLInventoryModelFetchDescendentsResponder::httpFailure()
-{
- LL_WARNS() << dumpResponse() << LL_ENDL;
- LLInventoryModelBackgroundFetch *fetcher = LLInventoryModelBackgroundFetch::getInstance();
-
- LL_INFOS() << dumpResponse() << LL_ENDL;
-
- fetcher->incrFetchCount(-1);
- if (getStatus()==HTTP_INTERNAL_ERROR) // timed out or curl failure
- {
- 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"];
- const BOOL recursive = getIsRecursive(folder_id);
- fetcher->mFetchQueue.push_front(LLInventoryModelBackgroundFetch::FetchQueueInfo(folder_id, recursive));
- }
- }
- else
+ if (mFetchCount)
{
- if (fetcher->isBulkFetchProcessingComplete())
- {
- fetcher->setAllFoldersFetched();
- }
- }
- gInventory.notifyObservers();
-}
-
-BOOL LLInventoryModelFetchDescendentsResponder::getIsRecursive(const LLUUID& cat_id) const
-{
- return (std::find(mRecursiveCatUUIDs.begin(),mRecursiveCatUUIDs.end(), cat_id) != mRecursiveCatUUIDs.end());
-}
-// Bundle up a bunch of requests to send all at once.
-// static
-void LLInventoryModelBackgroundFetch::bulkFetch()
-{
- //Background fetch is called from gIdleCallbacks in a loop until background fetch is stopped.
- //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.
- LLViewerRegion* region = gAgent.getRegion();
- if (!region) return;
-
- 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.
+ // Process completed HTTP requests
+ gInventory.handleResponses(false);
}
- if (gDisconnected ||
- (mFetchCount > max_concurrent_fetches) ||
+ if ((mFetchCount > max_concurrent_fetches) ||
(mFetchTimer.getElapsedTimeF32() < mMinTimeBetweenFetches))
{
- return; // just bail if we are disconnected
+ return;
}
- U32 item_count=0;
- U32 folder_count=0;
- U32 max_batch_size=5;
+ U32 item_count(0);
+ U32 folder_count(0);
- U32 sort_order = gSavedSettings.getU32(LLInventoryPanel::DEFAULT_SORT_ORDER) & 0x1;
+ const U32 sort_order(gSavedSettings.getU32(LLInventoryPanel::DEFAULT_SORT_ORDER) & 0x1);
uuid_vec_t recursive_cats;
@@ -614,27 +504,27 @@ void LLInventoryModelBackgroundFetch::bulkFetch()
LLSD item_request_body;
LLSD item_request_body_lib;
- while (!mFetchQueue.empty()
+ while (! mFetchQueue.empty()
&& (item_count + folder_count) < max_batch_size)
{
- const FetchQueueInfo& fetch_info = mFetchQueue.front();
+ const FetchQueueInfo & fetch_info(mFetchQueue.front());
if (fetch_info.mIsCategory)
{
- const LLUUID &cat_id = fetch_info.mUUID;
+ const LLUUID & cat_id(fetch_info.mUUID);
if (cat_id.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;
+ folder_sd["sort_order"] = LLSD::Integer(sort_order);
+ folder_sd["fetch_folders"] = LLSD::Boolean(FALSE);
+ folder_sd["fetch_items"] = LLSD::Boolean(TRUE);
folder_request_body["folders"].append(folder_sd);
folder_count++;
}
else
{
- const LLViewerInventoryCategory* cat = gInventory.getCategory(cat_id);
+ const LLViewerInventoryCategory * cat(gInventory.getCategory(cat_id));
if (cat)
{
@@ -643,21 +533,26 @@ void LLInventoryModelBackgroundFetch::bulkFetch()
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;
+ folder_sd["sort_order"] = LLSD::Integer(sort_order);
+ folder_sd["fetch_folders"] = LLSD::Boolean(TRUE); //(LLSD::Boolean)sFullFetchStarted;
+ folder_sd["fetch_items"] = LLSD::Boolean(TRUE);
if (ALEXANDRIA_LINDEN_ID == cat->getOwnerID())
+ {
folder_request_body_lib["folders"].append(folder_sd);
+ }
else
+ {
folder_request_body["folders"].append(folder_sd);
+ }
folder_count++;
}
+
// 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;
+ LLInventoryModel::cat_array_t * categories(NULL);
+ LLInventoryModel::item_array_t * items(NULL);
gInventory.getDirectDescendentsOf(cat->getUUID(), categories, items);
for (LLInventoryModel::cat_array_t::const_iterator it = categories->begin();
it != categories->end();
@@ -669,11 +564,14 @@ void LLInventoryModelBackgroundFetch::bulkFetch()
}
}
if (fetch_info.mRecursive)
+ {
recursive_cats.push_back(cat_id);
+ }
}
else
{
- LLViewerInventoryItem* itemp = gInventory.getItem(fetch_info.mUUID);
+ LLViewerInventoryItem * itemp(gInventory.getItem(fetch_info.mUUID));
+
if (itemp)
{
LLSD item_sd;
@@ -694,72 +592,80 @@ void LLInventoryModelBackgroundFetch::bulkFetch()
mFetchQueue.pop_front();
}
-
+
+ // Issue HTTP POST requests to fetch folders and items
+
if (item_count + folder_count > 0)
{
if (folder_count)
{
- std::string url = region->getCapability("FetchInventoryDescendents2");
- if ( !url.empty() )
+ if (folder_request_body["folders"].size())
{
- if (folder_request_body["folders"].size())
+ const std::string url(region->getCapability("FetchInventoryDescendents2"));
+
+ if (! url.empty())
{
- LLInventoryModelFetchDescendentsResponder *fetcher = new LLInventoryModelFetchDescendentsResponder(folder_request_body, recursive_cats);
- LLHTTPClient::post(url, folder_request_body, fetcher, 300.0);
+ BGFolderHttpHandler * handler(new BGFolderHttpHandler(folder_request_body, recursive_cats));
+ gInventory.requestPost(false, url, folder_request_body, handler, "Inventory Folder");
}
- if (folder_request_body_lib["folders"].size())
- {
- std::string url_lib = gAgent.getRegion()->getCapability("FetchLibDescendents2");
+ }
+
+ if (folder_request_body_lib["folders"].size())
+ {
+ const std::string url(region->getCapability("FetchLibDescendents2"));
- LLInventoryModelFetchDescendentsResponder *fetcher = new LLInventoryModelFetchDescendentsResponder(folder_request_body_lib, recursive_cats);
- LLHTTPClient::post(url_lib, folder_request_body_lib, fetcher, 300.0);
+ if (! url.empty())
+ {
+ BGFolderHttpHandler * handler(new BGFolderHttpHandler(folder_request_body_lib, recursive_cats));
+ gInventory.requestPost(false, url, folder_request_body_lib, handler, "Library Folder");
}
}
- }
+ } // if (folder_count)
+
if (item_count)
{
- std::string url;
-
if (item_request_body.size())
{
- url = region->getCapability("FetchInventory2");
- if (!url.empty())
+ const std::string url(region->getCapability("FetchInventory2"));
+
+ if (! url.empty())
{
LLSD body;
body["items"] = item_request_body;
-
- LLHTTPClient::post(url, body, new LLInventoryModelFetchItemResponder(body));
+ BGItemHttpHandler * handler(new BGItemHttpHandler(body));
+ gInventory.requestPost(false, url, body, handler, "Inventory Item");
}
}
if (item_request_body_lib.size())
{
+ const std::string url(region->getCapability("FetchLib2"));
- url = region->getCapability("FetchLib2");
- if (!url.empty())
+ if (! url.empty())
{
LLSD body;
body["items"] = item_request_body_lib;
-
- LLHTTPClient::post(url, body, new LLInventoryModelFetchItemResponder(body));
+ BGItemHttpHandler * handler(new BGItemHttpHandler(body));
+ gInventory.requestPost(false, url, body, handler, "Library Item");
}
}
- }
+ } // if (item_count)
+
mFetchTimer.reset();
}
-
else if (isBulkFetchProcessingComplete())
{
setAllFoldersFetched();
}
}
-bool LLInventoryModelBackgroundFetch::fetchQueueContainsNoDescendentsOf(const LLUUID& cat_id) const
+bool LLInventoryModelBackgroundFetch::fetchQueueContainsNoDescendentsOf(const LLUUID & cat_id) const
{
for (fetch_queue_t::const_iterator it = mFetchQueue.begin();
- it != mFetchQueue.end(); ++it)
+ it != mFetchQueue.end();
+ ++it)
{
- const LLUUID& fetch_id = (*it).mUUID;
+ const LLUUID & fetch_id = (*it).mUUID;
if (gInventory.isObjectDescendentOf(fetch_id, cat_id))
return false;
}
@@ -767,3 +673,257 @@ bool LLInventoryModelBackgroundFetch::fetchQueueContainsNoDescendentsOf(const LL
}
+// Anonymous Namespace Definitions
+
+namespace
+{
+
+// ==== BGFolderHttpHandler ====
+
+void BGFolderHttpHandler::onCompleted(LLCore::HttpHandle handle, LLCore::HttpResponse * response)
+{
+ LLCore::HttpStatus status(response->getStatus());
+ if (! status)
+ {
+ processFailure(status, response);
+ }
+ else
+ {
+ LLCore::BufferArray * body(response->getBody());
+ if (! body || ! body->size())
+ {
+ LL_WARNS(LOG_INV) << "Missing data in inventory folder query." << LL_ENDL;
+ processFailure("HTTP response missing expected body", response);
+ goto only_exit;
+ }
+
+ LLCore::BufferArrayStream bas(body);
+ LLSD body_llsd;
+ S32 parse_status(LLSDSerialize::fromXML(body_llsd, bas));
+ if (LLSDParser::PARSE_FAILURE == parse_status)
+ {
+ // INFOS-level logging will occur on the parsed failure
+ processFailure("HTTP response contained malformed LLSD", response);
+ goto only_exit;
+ }
+
+ // Okay, process data if possible
+ processData(body_llsd, response);
+ }
+
+only_exit:
+ // Must delete on completion.
+ delete this;
+}
+
+
+void BGFolderHttpHandler::processData(LLSD & content, LLCore::HttpResponse * response)
+{
+ if (! content.isMap())
+ {
+ processFailure("LLSD response not a map", response);
+ return;
+ }
+
+ LLInventoryModelBackgroundFetch * fetcher(LLInventoryModelBackgroundFetch::getInstance());
+ if (content.has("folders"))
+ {
+ LLSD folders(content["folders"]);
+
+ for (LLSD::array_const_iterator folder_it = folders.beginArray();
+ folder_it != 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.
+ //{
+ // LL_WARNS(LOG_INV) << "Got a UpdateInventoryItem for the wrong agent."
+ // << LL_ENDL;
+ // break;
+ //}
+
+ LLUUID parent_id(folder_sd["folder_id"].asUUID());
+ LLUUID owner_id(folder_sd["owner_id"].asUUID());
+ S32 version(folder_sd["version"].asInteger());
+ S32 descendents(folder_sd["descendents"].asInteger());
+ LLPointer<LLViewerInventoryCategory> tcategory = new LLViewerInventoryCategory(owner_id);
+
+ if (parent_id.isNull())
+ {
+ LLSD items(folder_sd["items"]);
+ LLPointer<LLViewerInventoryItem> titem = new LLViewerInventoryItem;
+
+ for (LLSD::array_const_iterator item_it = items.beginArray();
+ item_it != 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();
+ }
+ }
+ }
+
+ LLViewerInventoryCategory * pcat(gInventory.getCategory(parent_id));
+ if (! pcat)
+ {
+ continue;
+ }
+
+ LLSD categories(folder_sd["categories"]);
+ for (LLSD::array_const_iterator category_it = categories.beginArray();
+ category_it != categories.endArray();
+ ++category_it)
+ {
+ LLSD category(*category_it);
+ tcategory->fromLLSD(category);
+
+ const bool recursive(getIsRecursive(tcategory->getUUID()));
+ if (recursive)
+ {
+ fetcher->addRequestAtBack(tcategory->getUUID(), recursive, true);
+ }
+ else if (! gInventory.isCategoryComplete(tcategory->getUUID()))
+ {
+ gInventory.updateCategory(tcategory);
+ }
+ }
+
+ LLSD items(folder_sd["items"]);
+ LLPointer<LLViewerInventoryItem> titem = new LLViewerInventoryItem;
+ for (LLSD::array_const_iterator item_it = items.beginArray();
+ item_it != 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"))
+ {
+ LLSD bad_folders(content["bad_folders"]);
+ for (LLSD::array_const_iterator folder_it = bad_folders.beginArray();
+ folder_it != bad_folders.endArray();
+ ++folder_it)
+ {
+ // *TODO: Stop copying data
+ LLSD folder_sd(*folder_it);
+
+ // These folders failed on the dataserver. We probably don't want to retry them.
+ LL_WARNS(LOG_INV) << "Folder " << folder_sd["folder_id"].asString()
+ << "Error: " << folder_sd["error"].asString() << LL_ENDL;
+ }
+ }
+
+ if (fetcher->isBulkFetchProcessingComplete())
+ {
+ LL_INFOS(LOG_INV) << "Inventory fetch completed" << LL_ENDL;
+ fetcher->setAllFoldersFetched();
+ }
+
+ gInventory.notifyObservers();
+}
+
+
+void BGFolderHttpHandler::processFailure(LLCore::HttpStatus status, LLCore::HttpResponse * response)
+{
+ LL_WARNS(LOG_INV) << dumpResponse() << LL_ENDL;
+ LLInventoryModelBackgroundFetch *fetcher = LLInventoryModelBackgroundFetch::getInstance();
+
+ LL_INFOS(LOG_INV) << dumpResponse() << LL_ENDL;
+
+ // *FIX: Not the correct test here...
+ if (status == LLCore::HttpStatus(408)) // timed out or curl failure
+ {
+ 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"]);
+ const BOOL recursive = getIsRecursive(folder_id);
+ fetcher->addRequestAtFront(folder_id, recursive, true);
+ }
+ }
+ else
+ {
+ if (fetcher->isBulkFetchProcessingComplete())
+ {
+ fetcher->setAllFoldersFetched();
+ }
+ }
+ gInventory.notifyObservers();
+}
+
+
+void BGFolderHttpHandler::processFailure(const char * const reason, LLCore::HttpResponse * response)
+{
+ LL_WARNS(LOG_INV) << dumpResponse() << LL_ENDL;
+ LLInventoryModelBackgroundFetch *fetcher = LLInventoryModelBackgroundFetch::getInstance();
+
+ LL_INFOS(LOG_INV) << dumpResponse() << LL_ENDL;
+
+ if (true /* status == LLCore::HttpStatus(408)*/) // timed out or curl failure
+ {
+ 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"]);
+ const BOOL recursive = getIsRecursive(folder_id);
+ fetcher->addRequestAtFront(folder_id, recursive, true);
+ }
+ }
+ else
+ {
+ if (fetcher->isBulkFetchProcessingComplete())
+ {
+ fetcher->setAllFoldersFetched();
+ }
+ }
+ gInventory.notifyObservers();
+}
+
+
+bool BGFolderHttpHandler::getIsRecursive(const LLUUID & cat_id) const
+{
+ return std::find(mRecursiveCatUUIDs.begin(), mRecursiveCatUUIDs.end(), cat_id) != mRecursiveCatUUIDs.end();
+}
+
+
+// ==== BGItemHttpHandler ====
+
+// Nothing to implement here. All ctor/dtor changes.
+
+} // end namespace anonymous