diff options
-rw-r--r-- | ChangeLog.txt | 16 | ||||
-rw-r--r-- | linden/indra/llmessage/llassetstorage.cpp | 41 | ||||
-rw-r--r-- | linden/indra/newview/lltexturecache.cpp | 68 | ||||
-rw-r--r-- | linden/indra/newview/lltexturecache.h | 5 |
4 files changed, 104 insertions, 26 deletions
diff --git a/ChangeLog.txt b/ChangeLog.txt index 2cc6cca..5564136 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt | |||
@@ -3,3 +3,19 @@ | |||
3 | * linden/indra/newview/llviewerjointattachment.h (LLViewerJoint): | 3 | * linden/indra/newview/llviewerjointattachment.h (LLViewerJoint): |
4 | VWR-2685: Possible crash in bounding box (getBoundingBoxAgent()) | 4 | VWR-2685: Possible crash in bounding box (getBoundingBoxAgent()) |
5 | from hud attachments. | 5 | from hud attachments. |
6 | |||
7 | 2008-09-16 Jacek Antonelli <jacek.antonelli@gmail.com> | ||
8 | |||
9 | * linden/indra/newview/lltexturecache.cpp (purgeTextureFilesTimeSliced): | ||
10 | Skip "N files scheduled for deletion" message when nothing scheduled. | ||
11 | |||
12 | 2008-09-16 Nicholaz Beresford <nicholaz@blueflash.cc> | ||
13 | |||
14 | * linden/indra/newview/lltexturecache.cpp: | ||
15 | VWR-3878: Purging cache textures causes viewer to pause for many | ||
16 | seconds, with heavy disk activity. | ||
17 | * linden/indra/newview/lltexturecache.h: | ||
18 | Ditto. | ||
19 | |||
20 | * linden/indra/llmessage/llassetstorage.cpp: | ||
21 | VWR-3877: A nasty possible memory overwrite and two minor leaks. | ||
diff --git a/linden/indra/llmessage/llassetstorage.cpp b/linden/indra/llmessage/llassetstorage.cpp index a6077e5..83026ba 100644 --- a/linden/indra/llmessage/llassetstorage.cpp +++ b/linden/indra/llmessage/llassetstorage.cpp | |||
@@ -515,16 +515,19 @@ void LLAssetStorage::downloadCompleteCallback( | |||
515 | S32 result, | 515 | S32 result, |
516 | const LLUUID& file_id, | 516 | const LLUUID& file_id, |
517 | LLAssetType::EType file_type, | 517 | LLAssetType::EType file_type, |
518 | void* user_data, LLExtStat ext_status) | 518 | void* callback_parm_req, LLExtStat ext_status) |
519 | { | 519 | { |
520 | lldebugs << "LLAssetStorage::downloadCompleteCallback() for " << file_id | 520 | lldebugs << "LLAssetStorage::downloadCompleteCallback() for " << file_id |
521 | << "," << LLAssetType::lookup(file_type) << llendl; | 521 | << "," << LLAssetType::lookup(file_type) << llendl; |
522 | LLAssetRequest* req = (LLAssetRequest*)user_data; | 522 | |
523 | // be careful! req may be a ptr to memory already freed (a timeout does this) | ||
524 | LLAssetRequest* req = (LLAssetRequest*)callback_parm_req; | ||
523 | if(!req) | 525 | if(!req) |
524 | { | 526 | { |
525 | llwarns << "LLAssetStorage::downloadCompleteCallback called without" | 527 | llwarns << "LLAssetStorage::downloadCompleteCallback called without" |
526 | "a valid request." << llendl; | 528 | "a valid request." << llendl; |
527 | return; | 529 | // we can live with a null pointer, we're not allowed to deref the ptr anyway (see above) |
530 | // return; | ||
528 | } | 531 | } |
529 | if (!gAssetStorage) | 532 | if (!gAssetStorage) |
530 | { | 533 | { |
@@ -532,12 +535,10 @@ void LLAssetStorage::downloadCompleteCallback( | |||
532 | return; | 535 | return; |
533 | } | 536 | } |
534 | 537 | ||
535 | req->setUUID(file_id); | ||
536 | req->setType(file_type); | ||
537 | if (LL_ERR_NOERR == result) | 538 | if (LL_ERR_NOERR == result) |
538 | { | 539 | { |
539 | // we might have gotten a zero-size file | 540 | // we might have gotten a zero-size file |
540 | LLVFile vfile(gAssetStorage->mVFS, req->getUUID(), req->getType()); | 541 | LLVFile vfile(gAssetStorage->mVFS, file_id, file_type); |
541 | if (vfile.getSize() <= 0) | 542 | if (vfile.getSize() <= 0) |
542 | { | 543 | { |
543 | llwarns << "downloadCompleteCallback has non-existent or zero-size asset " << req->getUUID() << llendl; | 544 | llwarns << "downloadCompleteCallback has non-existent or zero-size asset " << req->getUUID() << llendl; |
@@ -556,7 +557,7 @@ void LLAssetStorage::downloadCompleteCallback( | |||
556 | { | 557 | { |
557 | request_list_t::iterator curiter = iter++; | 558 | request_list_t::iterator curiter = iter++; |
558 | LLAssetRequest* tmp = *curiter; | 559 | LLAssetRequest* tmp = *curiter; |
559 | if ((tmp->getUUID() == req->getUUID()) && (tmp->getType()== req->getType())) | 560 | if ((tmp->getUUID() == file_id) && (tmp->getType() == file_type)) |
560 | { | 561 | { |
561 | requests.push_front(tmp); | 562 | requests.push_front(tmp); |
562 | iter = gAssetStorage->mPendingDownloads.erase(curiter); | 563 | iter = gAssetStorage->mPendingDownloads.erase(curiter); |
@@ -569,7 +570,7 @@ void LLAssetStorage::downloadCompleteCallback( | |||
569 | LLAssetRequest* tmp = *curiter; | 570 | LLAssetRequest* tmp = *curiter; |
570 | if (tmp->mDownCallback) | 571 | if (tmp->mDownCallback) |
571 | { | 572 | { |
572 | tmp->mDownCallback(gAssetStorage->mVFS, req->getUUID(), req->getType(), tmp->mUserData, result, ext_status); | 573 | tmp->mDownCallback(gAssetStorage->mVFS, tmp->getUUID(), tmp->getType(), tmp->mUserData, result, ext_status); |
573 | } | 574 | } |
574 | delete tmp; | 575 | delete tmp; |
575 | } | 576 | } |
@@ -665,10 +666,10 @@ void LLAssetStorage::downloadEstateAssetCompleteCallback( | |||
665 | S32 result, | 666 | S32 result, |
666 | const LLUUID& file_id, | 667 | const LLUUID& file_id, |
667 | LLAssetType::EType file_type, | 668 | LLAssetType::EType file_type, |
668 | void* user_data, | 669 | void* callback_parm_req, |
669 | LLExtStat ext_status) | 670 | LLExtStat ext_status) |
670 | { | 671 | { |
671 | LLEstateAssetRequest *req = (LLEstateAssetRequest*)user_data; | 672 | LLEstateAssetRequest *req = (LLEstateAssetRequest*)callback_parm_req; |
672 | if(!req) | 673 | if(!req) |
673 | { | 674 | { |
674 | llwarns << "LLAssetStorage::downloadEstateAssetCompleteCallback called" | 675 | llwarns << "LLAssetStorage::downloadEstateAssetCompleteCallback called" |
@@ -682,12 +683,10 @@ void LLAssetStorage::downloadEstateAssetCompleteCallback( | |||
682 | return; | 683 | return; |
683 | } | 684 | } |
684 | 685 | ||
685 | req->setUUID(file_id); | ||
686 | req->setType(file_type); | ||
687 | if (LL_ERR_NOERR == result) | 686 | if (LL_ERR_NOERR == result) |
688 | { | 687 | { |
689 | // we might have gotten a zero-size file | 688 | // we might have gotten a zero-size file |
690 | LLVFile vfile(gAssetStorage->mVFS, req->getUUID(), req->getAType()); | 689 | LLVFile vfile(gAssetStorage->mVFS, file_id, file_type); |
691 | if (vfile.getSize() <= 0) | 690 | if (vfile.getSize() <= 0) |
692 | { | 691 | { |
693 | llwarns << "downloadCompleteCallback has non-existent or zero-size asset!" << llendl; | 692 | llwarns << "downloadCompleteCallback has non-existent or zero-size asset!" << llendl; |
@@ -697,7 +696,9 @@ void LLAssetStorage::downloadEstateAssetCompleteCallback( | |||
697 | } | 696 | } |
698 | } | 697 | } |
699 | 698 | ||
700 | req->mDownCallback(gAssetStorage->mVFS, req->getUUID(), req->getAType(), req->mUserData, result, ext_status); | 699 | req->mDownCallback(gAssetStorage->mVFS, file_id, file_type, req->mUserData, result, ext_status); |
700 | |||
701 | delete req; | ||
701 | } | 702 | } |
702 | 703 | ||
703 | void LLAssetStorage::getInvItemAsset(const LLHost &object_sim, const LLUUID &agent_id, const LLUUID &session_id, | 704 | void LLAssetStorage::getInvItemAsset(const LLHost &object_sim, const LLUUID &agent_id, const LLUUID &session_id, |
@@ -802,10 +803,10 @@ void LLAssetStorage::downloadInvItemCompleteCallback( | |||
802 | S32 result, | 803 | S32 result, |
803 | const LLUUID& file_id, | 804 | const LLUUID& file_id, |
804 | LLAssetType::EType file_type, | 805 | LLAssetType::EType file_type, |
805 | void* user_data, | 806 | void* callback_parm_req, |
806 | LLExtStat ext_status) | 807 | LLExtStat ext_status) |
807 | { | 808 | { |
808 | LLInvItemRequest *req = (LLInvItemRequest*)user_data; | 809 | LLInvItemRequest *req = (LLInvItemRequest*)callback_parm_req; |
809 | if(!req) | 810 | if(!req) |
810 | { | 811 | { |
811 | llwarns << "LLAssetStorage::downloadEstateAssetCompleteCallback called" | 812 | llwarns << "LLAssetStorage::downloadEstateAssetCompleteCallback called" |
@@ -818,12 +819,10 @@ void LLAssetStorage::downloadInvItemCompleteCallback( | |||
818 | return; | 819 | return; |
819 | } | 820 | } |
820 | 821 | ||
821 | req->setUUID(file_id); | ||
822 | req->setType(file_type); | ||
823 | if (LL_ERR_NOERR == result) | 822 | if (LL_ERR_NOERR == result) |
824 | { | 823 | { |
825 | // we might have gotten a zero-size file | 824 | // we might have gotten a zero-size file |
826 | LLVFile vfile(gAssetStorage->mVFS, req->getUUID(), req->getType()); | 825 | LLVFile vfile(gAssetStorage->mVFS, file_id, file_type); |
827 | if (vfile.getSize() <= 0) | 826 | if (vfile.getSize() <= 0) |
828 | { | 827 | { |
829 | llwarns << "downloadCompleteCallback has non-existent or zero-size asset!" << llendl; | 828 | llwarns << "downloadCompleteCallback has non-existent or zero-size asset!" << llendl; |
@@ -833,7 +832,9 @@ void LLAssetStorage::downloadInvItemCompleteCallback( | |||
833 | } | 832 | } |
834 | } | 833 | } |
835 | 834 | ||
836 | req->mDownCallback(gAssetStorage->mVFS, req->getUUID(), req->getType(), req->mUserData, result, ext_status); | 835 | req->mDownCallback(gAssetStorage->mVFS, file_id, file_type, req->mUserData, result, ext_status); |
836 | |||
837 | delete req; | ||
837 | } | 838 | } |
838 | 839 | ||
839 | ///////////////////////////////////////////////////////////////////////////////////////////////////////////////// | 840 | ///////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
diff --git a/linden/indra/newview/lltexturecache.cpp b/linden/indra/newview/lltexturecache.cpp index 22cb6c1..ac956e2 100644 --- a/linden/indra/newview/lltexturecache.cpp +++ b/linden/indra/newview/lltexturecache.cpp | |||
@@ -881,6 +881,8 @@ LLTextureCache::LLTextureCache(bool threaded) | |||
881 | 881 | ||
882 | LLTextureCache::~LLTextureCache() | 882 | LLTextureCache::~LLTextureCache() |
883 | { | 883 | { |
884 | purgeTextureFilesTimeSliced(TRUE); // force-flush all pending file deletes | ||
885 | |||
884 | apr_pool_destroy(mFileAPRPool); | 886 | apr_pool_destroy(mFileAPRPool); |
885 | } | 887 | } |
886 | 888 | ||
@@ -1187,7 +1189,7 @@ void LLTextureCache::purgeTextures(bool validate) | |||
1187 | return; | 1189 | return; |
1188 | } | 1190 | } |
1189 | 1191 | ||
1190 | LL_DEBUGS("TextureCache") << "TEXTURE CACHE: Reading Entries..." << LL_ENDL; | 1192 | LL_DEBUGS("TextureCache") << "TEXTURE CACHE: Reading " << num_entries << " Entries from " << mTexturesDirEntriesFileName << LL_ENDL; |
1191 | 1193 | ||
1192 | std::map<LLUUID, S32> entry_idx_map; | 1194 | std::map<LLUUID, S32> entry_idx_map; |
1193 | S64 total_size = 0; | 1195 | S64 total_size = 0; |
@@ -1216,7 +1218,7 @@ void LLTextureCache::purgeTextures(bool validate) | |||
1216 | LL_DEBUGS("TextureCache") << "TEXTURE CACHE: Validating: " << validate_idx << LL_ENDL; | 1218 | LL_DEBUGS("TextureCache") << "TEXTURE CACHE: Validating: " << validate_idx << LL_ENDL; |
1217 | } | 1219 | } |
1218 | 1220 | ||
1219 | S64 min_cache_size = (sCacheMaxTexturesSize * 9) / 10; | 1221 | S64 min_cache_size = sCacheMaxTexturesSize / 100 * 95; |
1220 | S32 purge_count = 0; | 1222 | S32 purge_count = 0; |
1221 | S32 next_idx = 0; | 1223 | S32 next_idx = 0; |
1222 | for (S32 idx=0; idx<num_entries; idx++) | 1224 | for (S32 idx=0; idx<num_entries; idx++) |
@@ -1250,8 +1252,8 @@ void LLTextureCache::purgeTextures(bool validate) | |||
1250 | if (purge_entry) | 1252 | if (purge_entry) |
1251 | { | 1253 | { |
1252 | purge_count++; | 1254 | purge_count++; |
1253 | LL_DEBUGS("TextureCache") << "PURGING: " << filename << LL_ENDL; | 1255 | LL_DEBUGS("TextureCache") << "PURGING: " << filename << LL_ENDL; |
1254 | ll_apr_file_remove(filename, NULL); | 1256 | mFilesToDelete.push_back(filename); |
1255 | total_size -= entries[idx].mSize; | 1257 | total_size -= entries[idx].mSize; |
1256 | entries[idx].mSize = 0; | 1258 | entries[idx].mSize = 0; |
1257 | } | 1259 | } |
@@ -1266,7 +1268,11 @@ void LLTextureCache::purgeTextures(bool validate) | |||
1266 | } | 1268 | } |
1267 | num_entries = next_idx; | 1269 | num_entries = next_idx; |
1268 | 1270 | ||
1269 | LL_DEBUGS("TextureCache") << "TEXTURE CACHE: Writing Entries: " << num_entries << LL_ENDL; | 1271 | mTimeLastFileDelete.reset(); |
1272 | |||
1273 | LL_DEBUGS("TextureCache") << "TEXTURE CACHE: Writing Entries: " | ||
1274 | << num_entries << " (" << num_entries*sizeof(Entry)/1024 << "KB)" | ||
1275 | << LL_ENDL; | ||
1270 | 1276 | ||
1271 | ll_apr_file_remove(mTexturesDirEntriesFileName, NULL); | 1277 | ll_apr_file_remove(mTexturesDirEntriesFileName, NULL); |
1272 | ll_apr_file_write_ex(mTexturesDirEntriesFileName, NULL, | 1278 | ll_apr_file_write_ex(mTexturesDirEntriesFileName, NULL, |
@@ -1289,10 +1295,56 @@ void LLTextureCache::purgeTextures(bool validate) | |||
1289 | LL_INFOS("TextureCache") << "TEXTURE CACHE:" | 1295 | LL_INFOS("TextureCache") << "TEXTURE CACHE:" |
1290 | << " PURGED: " << purge_count | 1296 | << " PURGED: " << purge_count |
1291 | << " ENTRIES: " << num_entries | 1297 | << " ENTRIES: " << num_entries |
1292 | << " CACHE SIZE: " << total_size / 1024*1024 << " MB" | 1298 | << " CACHE SIZE: " << total_size/1024/1024 << " MB" |
1293 | << llendl; | 1299 | << llendl; |
1294 | } | 1300 | } |
1295 | 1301 | ||
1302 | |||
1303 | void LLTextureCache::purgeTextureFilesTimeSliced(BOOL force_all) | ||
1304 | { | ||
1305 | LLMutexLock lock(&mHeaderMutex); | ||
1306 | |||
1307 | F32 delay_between_passes = 1.0f; // seconds | ||
1308 | F32 max_time_per_pass = 0.1f; // seconds | ||
1309 | |||
1310 | if (!force_all && mTimeLastFileDelete.getElapsedTimeF32() <= delay_between_passes) | ||
1311 | { | ||
1312 | return; | ||
1313 | } | ||
1314 | |||
1315 | LLTimer timer; | ||
1316 | S32 howmany = 0; | ||
1317 | |||
1318 | if (mFilesToDelete.size() > 0) | ||
1319 | { | ||
1320 | llinfos << "TEXTURE CACHE: " << mFilesToDelete.size() << " files scheduled for deletion" << llendl; | ||
1321 | } | ||
1322 | |||
1323 | for (LLTextureCache::filename_list_t::iterator iter = mFilesToDelete.begin(); iter!=mFilesToDelete.end(); ) | ||
1324 | { | ||
1325 | LLTextureCache::filename_list_t::iterator iter2 = iter++; | ||
1326 | ll_apr_file_remove(*iter2, NULL); | ||
1327 | mFilesToDelete.erase(iter2); | ||
1328 | howmany++; | ||
1329 | |||
1330 | if (!force_all && timer.getElapsedTimeF32() > max_time_per_pass) | ||
1331 | { | ||
1332 | break; | ||
1333 | } | ||
1334 | } | ||
1335 | |||
1336 | if (!mFilesToDelete.empty()) | ||
1337 | { | ||
1338 | llinfos << "TEXTURE CACHE: "<< howmany << " files deleted (" | ||
1339 | << mFilesToDelete.size() << " files left for next pass)" | ||
1340 | << llendl; | ||
1341 | } | ||
1342 | |||
1343 | mTimeLastFileDelete.reset(); | ||
1344 | } | ||
1345 | |||
1346 | |||
1347 | |||
1296 | ////////////////////////////////////////////////////////////////////////////// | 1348 | ////////////////////////////////////////////////////////////////////////////// |
1297 | 1349 | ||
1298 | // call lockWorkers() first! | 1350 | // call lockWorkers() first! |
@@ -1462,6 +1514,10 @@ LLTextureCache::handle_t LLTextureCache::writeToCache(const LLUUID& id, U32 prio | |||
1462 | purgeTextures(false); | 1514 | purgeTextures(false); |
1463 | mDoPurge = FALSE; | 1515 | mDoPurge = FALSE; |
1464 | } | 1516 | } |
1517 | |||
1518 | purgeTextureFilesTimeSliced(); // purge textures from cache in a non-hiccup-way | ||
1519 | |||
1520 | |||
1465 | if (datasize >= TEXTURE_CACHE_ENTRY_SIZE) | 1521 | if (datasize >= TEXTURE_CACHE_ENTRY_SIZE) |
1466 | { | 1522 | { |
1467 | LLMutexLock lock(&mWorkersMutex); | 1523 | LLMutexLock lock(&mWorkersMutex); |
diff --git a/linden/indra/newview/lltexturecache.h b/linden/indra/newview/lltexturecache.h index f083dd0..e15a88b 100644 --- a/linden/indra/newview/lltexturecache.h +++ b/linden/indra/newview/lltexturecache.h | |||
@@ -119,6 +119,7 @@ private: | |||
119 | void readHeaderCache(apr_pool_t* poolp = NULL); | 119 | void readHeaderCache(apr_pool_t* poolp = NULL); |
120 | void purgeAllTextures(bool purge_directories); | 120 | void purgeAllTextures(bool purge_directories); |
121 | void purgeTextures(bool validate); | 121 | void purgeTextures(bool validate); |
122 | void purgeTextureFilesTimeSliced(BOOL force_all = FALSE); | ||
122 | S32 getHeaderCacheEntry(const LLUUID& id, bool touch, S32* imagesize = NULL); | 123 | S32 getHeaderCacheEntry(const LLUUID& id, bool touch, S32* imagesize = NULL); |
123 | bool removeHeaderCacheEntry(const LLUUID& id); | 124 | bool removeHeaderCacheEntry(const LLUUID& id); |
124 | void lockHeaders() { mHeaderMutex.lock(); } | 125 | void lockHeaders() { mHeaderMutex.lock(); } |
@@ -140,6 +141,10 @@ private: | |||
140 | 141 | ||
141 | typedef std::vector<std::pair<LLPointer<Responder>, bool> > responder_list_t; | 142 | typedef std::vector<std::pair<LLPointer<Responder>, bool> > responder_list_t; |
142 | responder_list_t mCompletedList; | 143 | responder_list_t mCompletedList; |
144 | |||
145 | typedef std::list<std::string> filename_list_t; | ||
146 | filename_list_t mFilesToDelete; | ||
147 | LLTimer mTimeLastFileDelete; | ||
143 | 148 | ||
144 | BOOL mReadOnly; | 149 | BOOL mReadOnly; |
145 | 150 | ||