aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/newview/llinventorymodel.cpp
diff options
context:
space:
mode:
authorJacek Antonelli2008-08-15 23:45:34 -0500
committerJacek Antonelli2008-08-15 23:45:34 -0500
commitcd17687f01420952712a500107e0f93e7ab8d5f8 (patch)
treece48c2b706f2c1176290e39fb555fbdf6648ce01 /linden/indra/newview/llinventorymodel.cpp
parentSecond Life viewer sources 1.19.0.5 (diff)
downloadmeta-impy-cd17687f01420952712a500107e0f93e7ab8d5f8.zip
meta-impy-cd17687f01420952712a500107e0f93e7ab8d5f8.tar.gz
meta-impy-cd17687f01420952712a500107e0f93e7ab8d5f8.tar.bz2
meta-impy-cd17687f01420952712a500107e0f93e7ab8d5f8.tar.xz
Second Life viewer sources 1.19.1.0
Diffstat (limited to 'linden/indra/newview/llinventorymodel.cpp')
-rw-r--r--linden/indra/newview/llinventorymodel.cpp301
1 files changed, 299 insertions, 2 deletions
diff --git a/linden/indra/newview/llinventorymodel.cpp b/linden/indra/newview/llinventorymodel.cpp
index 9fb5ae9..feab282 100644
--- a/linden/indra/newview/llinventorymodel.cpp
+++ b/linden/indra/newview/llinventorymodel.cpp
@@ -47,6 +47,7 @@
47#include "llviewerinventory.h" 47#include "llviewerinventory.h"
48#include "llviewermessage.h" 48#include "llviewermessage.h"
49#include "llviewerwindow.h" 49#include "llviewerwindow.h"
50#include "llviewerregion.h"
50#include "llappviewer.h" 51#include "llappviewer.h"
51#include "lldbstrings.h" 52#include "lldbstrings.h"
52#include "llviewerstats.h" 53#include "llviewerstats.h"
@@ -54,6 +55,8 @@
54#include "llnotify.h" 55#include "llnotify.h"
55#include "llcallbacklist.h" 56#include "llcallbacklist.h"
56#include "llpreview.h" 57#include "llpreview.h"
58#include "llviewercontrol.h"
59#include "llsdutil.h"
57#include <deque> 60#include <deque>
58 61
59//#define DIFF_INVENTORY_FILES 62//#define DIFF_INVENTORY_FILES
@@ -69,6 +72,8 @@ F32 LLInventoryModel::sMinTimeBetweenFetches = 0.3f;
69F32 LLInventoryModel::sMaxTimeBetweenFetches = 10.f; 72F32 LLInventoryModel::sMaxTimeBetweenFetches = 10.f;
70BOOL LLInventoryModel::sTimelyFetchPending = FALSE; 73BOOL LLInventoryModel::sTimelyFetchPending = FALSE;
71LLFrameTimer LLInventoryModel::sFetchTimer; 74LLFrameTimer LLInventoryModel::sFetchTimer;
75LLInventoryModel::cat_map_t LLInventoryModel::sBulkFetchMap;
76S16 LLInventoryModel::sBulkFetchCount = 0;
72 77
73// RN: for some reason, using std::queue in the header file confuses the compiler which things it's an xmlrpc_queue 78// RN: for some reason, using std::queue in the header file confuses the compiler which things it's an xmlrpc_queue
74static std::deque<LLUUID> sFetchQueue; 79static std::deque<LLUUID> sFetchQueue;
@@ -1002,6 +1007,286 @@ void LLInventoryModel::fetchDescendentsOf(const LLUUID& folder_id)
1002 } 1007 }
1003} 1008}
1004 1009
1010//Initialize statics.
1011LLAlertDialog* LLInventoryModel::fetchDescendentsResponder::sRetryDialog=NULL;
1012LLSD LLInventoryModel::fetchDescendentsResponder::sRetrySD;
1013
1014bool LLInventoryModel::isBulkFetchProcessingComplete()
1015{
1016 return ( (sFetchQueue.empty()
1017 && sBulkFetchMap.empty()
1018 && sBulkFetchCount==0) ? TRUE : FALSE ) ;
1019}
1020
1021//If we get back a normal response, handle it here
1022void LLInventoryModel::fetchDescendentsResponder::result(const LLSD& content)
1023{
1024 if (content.has("folders"))
1025 {
1026 for(LLSD::array_const_iterator folder_it = content["folders"].beginArray();
1027 folder_it != content["folders"].endArray();
1028 ++folder_it)
1029 {
1030 LLSD folder_sd = *folder_it;
1031
1032
1033 LLUUID agent_id = folder_sd["agent-id"];
1034
1035 if(agent_id != gAgent.getID()) //This should never happen.
1036 {
1037 llwarns << "Got a UpdateInventoryItem for the wrong agent."
1038 << llendl;
1039 break;
1040 }
1041 LLUUID parent_id = folder_sd["folder-id"];
1042 LLUUID owner_id = folder_sd["owner-id"];
1043 S32 version = (S32)folder_sd["version"].asInteger();
1044 S32 descendents = (S32)folder_sd["descendents"].asInteger();
1045 LLPointer<LLViewerInventoryCategory> tcategory = new LLViewerInventoryCategory(owner_id);
1046 for(LLSD::array_const_iterator category_it = folder_sd["categories"].beginArray();
1047 category_it != folder_sd["categories"].endArray();
1048 ++category_it)
1049 {
1050 LLSD category = *category_it;
1051 tcategory->fromLLSD(category);
1052
1053 if (sFullFetchStarted)
1054 {
1055 sFetchQueue.push_back(tcategory->getUUID());
1056 }
1057 else if ( !gInventory.isCategoryComplete(tcategory->getUUID()) )
1058 {
1059 gInventory.updateCategory(tcategory);
1060 }
1061
1062 }
1063 LLPointer<LLViewerInventoryItem> titem = new LLViewerInventoryItem;
1064 for(LLSD::array_const_iterator item_it = folder_sd["items"].beginArray();
1065 item_it != folder_sd["items"].endArray();
1066 ++item_it)
1067 {
1068 LLSD item = *item_it;
1069 titem->unpackMessage(item);
1070
1071 gInventory.updateItem(titem);
1072 }
1073
1074 // set version and descendentcount according to message.
1075 LLViewerInventoryCategory* cat = gInventory.getCategory(parent_id);
1076 if(cat)
1077 {
1078 cat->setVersion(version);
1079 cat->setDescendentCount(descendents);
1080 }
1081
1082 }
1083 }
1084
1085 if (content.has("bad-folders"))
1086 {
1087 for(LLSD::array_const_iterator folder_it = content["bad-folders"].beginArray();
1088 folder_it != content["bad-folders"].endArray();
1089 ++folder_it)
1090 {
1091 LLSD folder_sd = *folder_it;
1092
1093 //These folders failed on the dataserver. We probably don't want to retry them.
1094 llinfos << "Folder " << folder_sd["folder-id"].asString()
1095 << "Error: " << folder_sd["error"].asString() << llendl;
1096 }
1097 }
1098
1099 LLInventoryModel::incrBulkFetch(-1);
1100
1101 if (isBulkFetchProcessingComplete())
1102 {
1103 llinfos << "Inventory fetch completed" << llendl;
1104 if (sFullFetchStarted)
1105 {
1106 sAllFoldersFetched = TRUE;
1107 }
1108 stopBackgroundFetch();
1109 }
1110
1111 gInventory.notifyObservers();
1112}
1113
1114//If we get back an error (not found, etc...), handle it here
1115void LLInventoryModel::fetchDescendentsResponder::error(U32 status, const std::string& reason)
1116{
1117 llinfos << "fetchDescendentsResponder::error "
1118 << status << ": " << reason << llendl;
1119
1120 LLInventoryModel::incrBulkFetch(-1);
1121
1122 if (status==499) //timed out. Let's be awesome!
1123 {
1124 for(LLSD::array_const_iterator folder_it = mRequestSD["folders"].beginArray();
1125 folder_it != mRequestSD["folders"].endArray();
1126 ++folder_it)
1127 {
1128 LLSD folder_sd = *folder_it;
1129 sRetrySD["folders"].append(folder_sd);
1130 }
1131 sMinTimeBetweenFetches = 10.0f; //Add 10 seconds for every time out in this sequence.
1132
1133 if (!sRetryDialog) //The dialog isn't up. Prompt the resident.
1134 {
1135 sRetryDialog = gViewerWindow->alertXml("RetryFetchInventoryDescendents", onClickRetry, this);
1136 }
1137 }
1138 else
1139 {
1140 if (isBulkFetchProcessingComplete())
1141 {
1142 if (sFullFetchStarted)
1143 {
1144 sAllFoldersFetched = TRUE;
1145 }
1146 stopBackgroundFetch();
1147 }
1148 }
1149 gInventory.notifyObservers();
1150}
1151
1152void LLInventoryModel::fetchDescendentsResponder::onClickRetry(S32 option, void* userdata)
1153{
1154 if (option == 0)
1155 {
1156 std::string url = gAgent.getRegion()->getCapability("FetchInventoryDescendents");
1157
1158 if (!url.empty()) //Capability found. Build up LLSD and use it.
1159 {
1160 LLSD body = sRetrySD;
1161 LLInventoryModel::incrBulkFetch(1);
1162 LLHTTPClient::post(url, body, new LLInventoryModel::fetchDescendentsResponder(body),300);
1163 }
1164 }
1165 else
1166 {
1167 if (isBulkFetchProcessingComplete())
1168 {
1169 if (sFullFetchStarted)
1170 {
1171 sAllFoldersFetched = TRUE;
1172 }
1173 stopBackgroundFetch();
1174 }
1175 }
1176 sRetryDialog=NULL;
1177 sRetrySD.clear();
1178}
1179
1180//static Bundle up a bunch of requests to send all at once.
1181void LLInventoryModel::bulkFetch(std::string url)
1182{
1183 //Background fetch is called from gIdleCallbacks in a loop until background fetch is stopped.
1184 //If there are items in sFetchQueue, we want to check the time since the last bulkFetch was
1185 //sent. If it exceeds our retry time, go ahead and fire off another batch.
1186 //Stopbackgroundfetch will be run from the Responder instead of here.
1187
1188 S16 max_concurrent_fetches=8;
1189 F32 new_min_time = 0.5f; //HACK! Clean this up when old code goes away entirely.
1190 if (sMinTimeBetweenFetches <= new_min_time) sMinTimeBetweenFetches=new_min_time; //HACK! See above.
1191
1192 if(gDisconnected
1193 || sBulkFetchCount > max_concurrent_fetches
1194 || sFetchTimer.getElapsedTimeF32() < sMinTimeBetweenFetches)
1195 {
1196 return; // just bail if we are disconnected.
1197 }
1198
1199 //HACK. This is inelegant. We're shuffling a dequeue to a map to get rid of
1200 //redundant requests. When we get rid of the old code entirely, we can change
1201 //the dequeue to a map. In the new model, there is no benefit to queue order.
1202 U32 folder_count=0;
1203 U32 max_batch_size=10;
1204 while( !(sFetchQueue.empty() ) )
1205 {
1206 LLViewerInventoryCategory* cat = gInventory.getCategory(sFetchQueue.front());
1207
1208 if (cat)
1209 {
1210 if ( !gInventory.isCategoryComplete(cat->getUUID()) ) //grab this folder.
1211 {
1212 sBulkFetchMap[(cat->getUUID())] = cat;
1213 }
1214 else if (sFullFetchStarted)
1215 { //Already have this folder but append child folders to list.
1216 // add all children to queue
1217 parent_cat_map_t::iterator cat_it = gInventory.mParentChildCategoryTree.find(cat->getUUID());
1218 if (cat_it != gInventory.mParentChildCategoryTree.end())
1219 {
1220 cat_array_t* child_categories = cat_it->second;
1221
1222 for (S32 child_num = 0; child_num < child_categories->count(); child_num++)
1223 {
1224 sFetchQueue.push_back(child_categories->get(child_num)->getUUID());
1225 }
1226 }
1227
1228 }
1229 }
1230 sFetchQueue.pop_front();
1231 }
1232
1233
1234 if (!sBulkFetchMap.empty()) //There's stuff to fetch.
1235 {
1236 U32 sort_order = gSavedSettings.getU32("InventorySortOrder") & 0x1;
1237
1238 LLSD body;
1239
1240 cat_map_t::iterator iter=sBulkFetchMap.begin();
1241 while( iter!=sBulkFetchMap.end() && (folder_count < max_batch_size) )
1242 {
1243 LLViewerInventoryCategory* cat = iter->second;
1244
1245 if (cat && !gInventory.isCategoryComplete(cat->getUUID()) ) //Category exists
1246 {
1247 BOOL fetchItems=TRUE;
1248 if ( sFullFetchStarted
1249 && gInventory.isCategoryComplete(cat->getUUID()) )
1250 {
1251 fetchItems=FALSE;
1252 }
1253
1254 LLSD folder_sd;
1255 folder_sd["folder-id"] = cat->getUUID();
1256 folder_sd["owner-id"] = cat->getOwnerID();
1257 folder_sd["sort-order"] = (LLSD::Integer)sort_order;
1258 folder_sd["fetch-folders"] = (LLSD::Boolean)sFullFetchStarted;
1259 folder_sd["fetch-items"] = (LLSD::Boolean)fetchItems;
1260 body["folders"].append(folder_sd);
1261
1262 folder_count++;
1263 }
1264 sBulkFetchMap.erase(iter);
1265 iter=sBulkFetchMap.begin();
1266 }
1267
1268 if (iter == sBulkFetchMap.end()) sBulkFetchMap.clear();
1269
1270 if (folder_count > 0)
1271 {
1272 sBulkFetchCount++;
1273
1274 LLHTTPClient::post(url, body, new LLInventoryModel::fetchDescendentsResponder(body));
1275 sFetchTimer.reset();
1276 }
1277
1278 }
1279
1280 if (isBulkFetchProcessingComplete())
1281 {
1282 if (sFullFetchStarted)
1283 {
1284 sAllFoldersFetched = TRUE;
1285 }
1286 stopBackgroundFetch();
1287 }
1288}
1289
1005// static 1290// static
1006bool LLInventoryModel::isEverythingFetched() 1291bool LLInventoryModel::isEverythingFetched()
1007{ 1292{
@@ -1049,6 +1334,9 @@ void LLInventoryModel::stopBackgroundFetch()
1049 { 1334 {
1050 sBackgroundFetchActive = FALSE; 1335 sBackgroundFetchActive = FALSE;
1051 gIdleCallbacks.deleteFunction(&LLInventoryModel::backgroundFetch, NULL); 1336 gIdleCallbacks.deleteFunction(&LLInventoryModel::backgroundFetch, NULL);
1337 sBulkFetchCount=0;
1338 sMinTimeBetweenFetches=0.0f;
1339// sFullFetchStarted=FALSE;
1052 } 1340 }
1053} 1341}
1054 1342
@@ -1057,6 +1345,15 @@ void LLInventoryModel::backgroundFetch(void*)
1057{ 1345{
1058 if (sBackgroundFetchActive) 1346 if (sBackgroundFetchActive)
1059 { 1347 {
1348 //If we'll be using the capability, we'll be sending batches and the background thing isn't as important.
1349 std::string url = gAgent.getRegion()->getCapability("FetchInventoryDescendents");
1350 if (!url.empty())
1351 {
1352 bulkFetch(url);
1353 return;
1354 }
1355
1356 //DEPRECATED OLD CODE FOLLOWS.
1060 // no more categories to fetch, stop fetch process 1357 // no more categories to fetch, stop fetch process
1061 if (sFetchQueue.empty()) 1358 if (sFetchQueue.empty())
1062 { 1359 {
@@ -3063,8 +3360,8 @@ void LLInventoryFetchDescendentsObserver::fetchDescendents(
3063 if(!cat) continue; 3360 if(!cat) continue;
3064 if(!isComplete(cat)) 3361 if(!isComplete(cat))
3065 { 3362 {
3066 cat->fetchDescendents(); 3363 cat->fetchDescendents(); //blindly fetch it without seeing if anything else is fetching it.
3067 mIncompleteFolders.push_back(*it); 3364 mIncompleteFolders.push_back(*it); //Add to list of things being downloaded for this observer.
3068 } 3365 }
3069 else 3366 else
3070 { 3367 {