diff options
author | Jacek Antonelli | 2008-08-15 23:45:34 -0500 |
---|---|---|
committer | Jacek Antonelli | 2008-08-15 23:45:34 -0500 |
commit | cd17687f01420952712a500107e0f93e7ab8d5f8 (patch) | |
tree | ce48c2b706f2c1176290e39fb555fbdf6648ce01 /linden/indra/newview/llinventorymodel.cpp | |
parent | Second Life viewer sources 1.19.0.5 (diff) | |
download | meta-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.cpp | 301 |
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; | |||
69 | F32 LLInventoryModel::sMaxTimeBetweenFetches = 10.f; | 72 | F32 LLInventoryModel::sMaxTimeBetweenFetches = 10.f; |
70 | BOOL LLInventoryModel::sTimelyFetchPending = FALSE; | 73 | BOOL LLInventoryModel::sTimelyFetchPending = FALSE; |
71 | LLFrameTimer LLInventoryModel::sFetchTimer; | 74 | LLFrameTimer LLInventoryModel::sFetchTimer; |
75 | LLInventoryModel::cat_map_t LLInventoryModel::sBulkFetchMap; | ||
76 | S16 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 |
74 | static std::deque<LLUUID> sFetchQueue; | 79 | static std::deque<LLUUID> sFetchQueue; |
@@ -1002,6 +1007,286 @@ void LLInventoryModel::fetchDescendentsOf(const LLUUID& folder_id) | |||
1002 | } | 1007 | } |
1003 | } | 1008 | } |
1004 | 1009 | ||
1010 | //Initialize statics. | ||
1011 | LLAlertDialog* LLInventoryModel::fetchDescendentsResponder::sRetryDialog=NULL; | ||
1012 | LLSD LLInventoryModel::fetchDescendentsResponder::sRetrySD; | ||
1013 | |||
1014 | bool 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 | ||
1022 | void 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 | ||
1115 | void 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 | |||
1152 | void 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. | ||
1181 | void 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 |
1006 | bool LLInventoryModel::isEverythingFetched() | 1291 | bool 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 | { |