00001
00032 #include "llviewerprecompiledheaders.h"
00033
00034 #include "lltexturecache.h"
00035
00036 #include "llapr.h"
00037 #include "lldir.h"
00038 #include "llimage.h"
00039 #include "lllfsthread.h"
00040 #include "llviewercontrol.h"
00041
00042 #define USE_LFS_READ 0
00043 #define USE_LFS_WRITE 0
00044
00045
00046 const S32 TEXTURE_CACHE_ENTRY_SIZE = FIRST_PACKET_SIZE;
00047
00048 class LLTextureCacheWorker : public LLWorkerClass
00049 {
00050 friend class LLTextureCache;
00051
00052 private:
00053 class ReadResponder : public LLLFSThread::Responder
00054 {
00055 public:
00056 ReadResponder(LLTextureCache* cache, handle_t handle) : mCache(cache), mHandle(handle) {}
00057 ~ReadResponder() {}
00058 void completed(S32 bytes)
00059 {
00060 mCache->lockWorkers();
00061 LLTextureCacheWorker* reader = mCache->getReader(mHandle);
00062 if (reader) reader->ioComplete(bytes);
00063 mCache->unlockWorkers();
00064 }
00065 LLTextureCache* mCache;
00066 LLTextureCacheWorker::handle_t mHandle;
00067 };
00068
00069 class WriteResponder : public LLLFSThread::Responder
00070 {
00071 public:
00072 WriteResponder(LLTextureCache* cache, handle_t handle) : mCache(cache), mHandle(handle) {}
00073 ~WriteResponder() {}
00074 void completed(S32 bytes)
00075 {
00076 mCache->lockWorkers();
00077 LLTextureCacheWorker* writer = mCache->getWriter(mHandle);
00078 if (writer) writer->ioComplete(bytes);
00079 mCache->unlockWorkers();
00080 }
00081 LLTextureCache* mCache;
00082 LLTextureCacheWorker::handle_t mHandle;
00083 };
00084
00085 public:
00086 LLTextureCacheWorker(LLTextureCache* cache, U32 priority, const LLUUID& id,
00087 U8* data, S32 datasize, S32 offset,
00088 S32 imagesize,
00089 LLTextureCache::Responder* responder)
00090 : LLWorkerClass(cache, "LLTextureCacheWorker"),
00091 mID(id),
00092 mCache(cache),
00093 mPriority(priority),
00094 mReadData(NULL),
00095 mWriteData(data),
00096 mDataSize(datasize),
00097 mOffset(offset),
00098 mImageSize(imagesize),
00099 mImageFormat(IMG_CODEC_J2C),
00100 mImageLocal(FALSE),
00101 mResponder(responder),
00102 mFileHandle(LLLFSThread::nullHandle()),
00103 mBytesToRead(0),
00104 mBytesRead(0)
00105 {
00106 mPriority &= LLWorkerThread::PRIORITY_LOWBITS;
00107 }
00108 ~LLTextureCacheWorker()
00109 {
00110 llassert_always(!haveWork());
00111 delete[] mReadData;
00112 }
00113
00114
00115 virtual bool doRead() = 0;
00116 virtual bool doWrite() = 0;
00117
00118 virtual bool doWork(S32 param);
00119
00120 handle_t read() { addWork(0, LLWorkerThread::PRIORITY_HIGH | mPriority); return mRequestHandle; }
00121 handle_t write() { addWork(1, LLWorkerThread::PRIORITY_HIGH | mPriority); return mRequestHandle; }
00122 bool complete() { return checkWork(); }
00123 void ioComplete(S32 bytes)
00124 {
00125 mBytesRead = bytes;
00126 setPriority(LLWorkerThread::PRIORITY_HIGH | mPriority);
00127 }
00128
00129 private:
00130 virtual void startWork(S32 param);
00131 virtual void finishWork(S32 param, bool completed);
00132 virtual void endWork(S32 param, bool aborted);
00133
00134 protected:
00135 LLTextureCache* mCache;
00136 U32 mPriority;
00137 LLUUID mID;
00138
00139 U8* mReadData;
00140 U8* mWriteData;
00141 S32 mDataSize;
00142 S32 mOffset;
00143 S32 mImageSize;
00144 EImageCodec mImageFormat;
00145 BOOL mImageLocal;
00146 LLPointer<LLTextureCache::Responder> mResponder;
00147 LLLFSThread::handle_t mFileHandle;
00148 S32 mBytesToRead;
00149 LLAtomicS32 mBytesRead;
00150 };
00151
00152 class LLTextureCacheLocalFileWorker : public LLTextureCacheWorker
00153 {
00154 public:
00155 LLTextureCacheLocalFileWorker(LLTextureCache* cache, U32 priority, const LLString& filename, const LLUUID& id,
00156 U8* data, S32 datasize, S32 offset,
00157 S32 imagesize,
00158 LLTextureCache::Responder* responder)
00159 : LLTextureCacheWorker(cache, priority, id, data, datasize, offset, imagesize, responder),
00160 mFileName(filename)
00161
00162 {
00163 }
00164
00165 virtual bool doRead();
00166 virtual bool doWrite();
00167
00168 private:
00169 LLString mFileName;
00170 };
00171
00172 bool LLTextureCacheLocalFileWorker::doRead()
00173 {
00174 S32 local_size = ll_apr_file_size(mFileName, mCache->getFileAPRPool());
00175
00176 if (local_size > 0 && mFileName.size() > 4)
00177 {
00178 mDataSize = local_size;
00179
00180 LLString extension = mFileName.substr(mFileName.size() - 3, 3);
00181
00182 mImageFormat = LLImageBase::getCodecFromExtension(extension);
00183
00184 if (mImageFormat == IMG_CODEC_INVALID)
00185 {
00186 llwarns << "Unrecognized file extension " << extension << " for local texture " << mFileName << llendl;
00187 mDataSize = 0;
00188 return true;
00189 }
00190 }
00191 else
00192 {
00193
00194 mDataSize = 0;
00195 return true;
00196 }
00197
00198 #if USE_LFS_READ
00199 if (mFileHandle == LLLFSThread::nullHandle())
00200 {
00201 mImageLocal = TRUE;
00202 mImageSize = local_size;
00203 if (!mDataSize || mDataSize + mOffset > local_size)
00204 {
00205 mDataSize = local_size - mOffset;
00206 }
00207 if (mDataSize <= 0)
00208 {
00209
00210 mDataSize = 0;
00211 return true;
00212 }
00213 mReadData = new U8[mDataSize];
00214 mBytesRead = -1;
00215 mBytesToRead = mDataSize;
00216 setPriority(LLWorkerThread::PRIORITY_LOW | mPriority);
00217 mFileHandle = LLLFSThread::sLocal->read(local_filename, mReadData, mOffset, mDataSize,
00218 new ReadResponder(mCache, mRequestHandle));
00219 return false;
00220 }
00221 else
00222 {
00223 if (mBytesRead >= 0)
00224 {
00225 if (mBytesRead != mBytesToRead)
00226 {
00227 llwarns << "Error reading file from local cache: " << local_filename
00228 << " Bytes: " << mDataSize << " Offset: " << mOffset
00229 << " / " << mDataSize << llendl;
00230 mDataSize = 0;
00231 delete[] mReadData;
00232 mReadData = NULL;
00233 }
00234 return true;
00235 }
00236 else
00237 {
00238 return false;
00239 }
00240 }
00241 #else
00242 if (!mDataSize || mDataSize > local_size)
00243 {
00244 mDataSize = local_size;
00245 }
00246 mReadData = new U8[mDataSize];
00247 S32 bytes_read = ll_apr_file_read_ex(mFileName, mCache->getFileAPRPool(),
00248 mReadData, mOffset, mDataSize);
00249 if (bytes_read != mDataSize)
00250 {
00251 llwarns << "Error reading file from local cache: " << mFileName
00252 << " Bytes: " << mDataSize << " Offset: " << mOffset
00253 << " / " << mDataSize << llendl;
00254 mDataSize = 0;
00255 delete[] mReadData;
00256 mReadData = NULL;
00257 }
00258 else
00259 {
00260 mImageSize = local_size;
00261 mImageLocal = TRUE;
00262 }
00263 return true;
00264 #endif
00265 }
00266
00267 bool LLTextureCacheLocalFileWorker::doWrite()
00268 {
00269
00270 return false;
00271 }
00272
00273 class LLTextureCacheRemoteWorker : public LLTextureCacheWorker
00274 {
00275 public:
00276 LLTextureCacheRemoteWorker(LLTextureCache* cache, U32 priority, const LLUUID& id,
00277 U8* data, S32 datasize, S32 offset,
00278 S32 imagesize,
00279 LLTextureCache::Responder* responder)
00280 : LLTextureCacheWorker(cache, priority, id, data, datasize, offset, imagesize, responder),
00281 mState(INIT)
00282 {
00283 }
00284
00285 virtual bool doRead();
00286 virtual bool doWrite();
00287
00288 private:
00289 enum e_state
00290 {
00291 INIT = 0,
00292 LOCAL = 1,
00293 CACHE = 2,
00294 HEADER = 3,
00295 BODY = 4
00296 };
00297
00298 e_state mState;
00299 };
00300
00301
00302
00303 void LLTextureCacheWorker::startWork(S32 param)
00304 {
00305 }
00306
00307 bool LLTextureCacheRemoteWorker::doRead()
00308 {
00309 S32 local_size = 0;
00310 std::string local_filename;
00311
00312 if (mState == INIT)
00313 {
00314 std::string filename = mCache->getLocalFileName(mID);
00315 local_filename = filename + ".j2c";
00316 local_size = ll_apr_file_size(local_filename, mCache->getFileAPRPool());
00317 if (local_size == 0)
00318 {
00319 local_filename = filename + ".tga";
00320 local_size = ll_apr_file_size(local_filename, mCache->getFileAPRPool());
00321 if (local_size > 0)
00322 {
00323 mImageFormat = IMG_CODEC_TGA;
00324 mDataSize = local_size;
00325 }
00326 }
00327 if (local_size > 0)
00328 {
00329 mState = LOCAL;
00330 }
00331 else
00332 {
00333 mState = CACHE;
00334 }
00335 }
00336
00337 if (mState == LOCAL)
00338 {
00339 #if USE_LFS_READ
00340 if (mFileHandle == LLLFSThread::nullHandle())
00341 {
00342 mImageLocal = TRUE;
00343 mImageSize = local_size;
00344 if (!mDataSize || mDataSize + mOffset > local_size)
00345 {
00346 mDataSize = local_size - mOffset;
00347 }
00348 if (mDataSize <= 0)
00349 {
00350
00351 mDataSize = 0;
00352 return true;
00353 }
00354 mReadData = new U8[mDataSize];
00355 mBytesRead = -1;
00356 mBytesToRead = mDataSize;
00357 setPriority(LLWorkerThread::PRIORITY_LOW | mPriority);
00358 mFileHandle = LLLFSThread::sLocal->read(local_filename, mReadData, mOffset, mDataSize,
00359 new ReadResponder(mCache, mRequestHandle));
00360 return false;
00361 }
00362 else
00363 {
00364 if (mBytesRead >= 0)
00365 {
00366 if (mBytesRead != mBytesToRead)
00367 {
00368 llwarns << "Error reading file from local cache: " << local_filename
00369 << " Bytes: " << mDataSize << " Offset: " << mOffset
00370 << " / " << mDataSize << llendl;
00371 mDataSize = 0;
00372 delete[] mReadData;
00373 mReadData = NULL;
00374 }
00375 return true;
00376 }
00377 else
00378 {
00379 return false;
00380 }
00381 }
00382 #else
00383 if (!mDataSize || mDataSize > local_size)
00384 {
00385 mDataSize = local_size;
00386 }
00387 mReadData = new U8[mDataSize];
00388 S32 bytes_read = ll_apr_file_read_ex(local_filename, mCache->getFileAPRPool(),
00389 mReadData, mOffset, mDataSize);
00390 if (bytes_read != mDataSize)
00391 {
00392 llwarns << "Error reading file from local cache: " << local_filename
00393 << " Bytes: " << mDataSize << " Offset: " << mOffset
00394 << " / " << mDataSize << llendl;
00395 mDataSize = 0;
00396 delete[] mReadData;
00397 mReadData = NULL;
00398 }
00399 else
00400 {
00401 mImageSize = local_size;
00402 mImageLocal = TRUE;
00403 }
00404 return true;
00405 #endif
00406 }
00407
00408 S32 idx = -1;
00409
00410 if (mState == CACHE)
00411 {
00412 llassert_always(mImageSize == 0);
00413 idx = mCache->getHeaderCacheEntry(mID, false, &mImageSize);
00414 if (idx >= 0 && mImageSize > mOffset)
00415 {
00416 llassert_always(mImageSize > 0);
00417 if (!mDataSize || mDataSize > mImageSize)
00418 {
00419 mDataSize = mImageSize;
00420 }
00421 mState = mOffset < TEXTURE_CACHE_ENTRY_SIZE ? HEADER : BODY;
00422 }
00423 else
00424 {
00425 mDataSize = 0;
00426 return true;
00427 }
00428 }
00429
00430 if (mState == HEADER)
00431 {
00432 #if USE_LFS_READ
00433 if (mFileHandle == LLLFSThread::nullHandle())
00434 {
00435 llassert_always(idx >= 0);
00436 llassert_always(mOffset < TEXTURE_CACHE_ENTRY_SIZE);
00437 S32 offset = idx * TEXTURE_CACHE_ENTRY_SIZE + mOffset;
00438 S32 size = TEXTURE_CACHE_ENTRY_SIZE - mOffset;
00439 llassert_always(mReadData == NULL);
00440 mReadData = new U8[size];
00441 mBytesRead = -1;
00442 mBytesToRead = size;
00443 setPriority(LLWorkerThread::PRIORITY_LOW | mPriority);
00444 mFileHandle = LLLFSThread::sLocal->read(mCache->mHeaderDataFileName,
00445 mReadData, offset, mBytesToRead,
00446 new ReadResponder(mCache, mRequestHandle));
00447 return false;
00448 }
00449 else
00450 {
00451 if (mBytesRead >= 0)
00452 {
00453 if (mBytesRead != mBytesToRead)
00454 {
00455 llwarns << "LLTextureCacheWorker: " << mID
00456 << " incorrect number of bytes read from header: " << mBytesRead
00457 << " != " << mBytesToRead << llendl;
00458 mDataSize = -1;
00459 return true;
00460 }
00461 if (mDataSize <= TEXTURE_CACHE_ENTRY_SIZE)
00462 {
00463 return true;
00464 }
00465 else
00466 {
00467 mFileHandle = LLLFSThread::nullHandle();
00468 mState = BODY;
00469 }
00470 }
00471 else
00472 {
00473 return false;
00474 }
00475 }
00476 #else
00477 llassert_always(idx >= 0);
00478 llassert_always(mOffset < TEXTURE_CACHE_ENTRY_SIZE);
00479 S32 offset = idx * TEXTURE_CACHE_ENTRY_SIZE + mOffset;
00480 S32 size = TEXTURE_CACHE_ENTRY_SIZE - mOffset;
00481 mReadData = new U8[size];
00482 S32 bytes_read = ll_apr_file_read_ex(mCache->mHeaderDataFileName, mCache->getFileAPRPool(),
00483 mReadData, offset, size);
00484 if (bytes_read != size)
00485 {
00486 llwarns << "LLTextureCacheWorker: " << mID
00487 << " incorrect number of bytes read from header: " << bytes_read
00488 << " / " << size << llendl;
00489 mDataSize = -1;
00490 return true;
00491 }
00492 if (mDataSize <= TEXTURE_CACHE_ENTRY_SIZE)
00493 {
00494 return true;
00495 }
00496 else
00497 {
00498 mState = BODY;
00499 }
00500 #endif
00501 }
00502
00503 if (mState == BODY)
00504 {
00505 #if USE_LFS_READ
00506 if (mFileHandle == LLLFSThread::nullHandle())
00507 {
00508 std::string filename = mCache->getTextureFileName(mID);
00509 S32 filesize = ll_apr_file_size(filename, mCache->getFileAPRPool());
00510 if (filesize > mOffset)
00511 {
00512 S32 datasize = TEXTURE_CACHE_ENTRY_SIZE + filesize;
00513 mDataSize = llmin(datasize, mDataSize);
00514 S32 data_offset = TEXTURE_CACHE_ENTRY_SIZE - mOffset;
00515 data_offset = llmax(data_offset, 0);
00516 S32 file_size = mDataSize - data_offset;
00517 S32 file_offset = mOffset - TEXTURE_CACHE_ENTRY_SIZE;
00518 file_offset = llmax(file_offset, 0);
00519
00520 llassert_always(mDataSize > 0);
00521 U8* data = new U8[mDataSize];
00522 if (data_offset > 0)
00523 {
00524 llassert_always(mReadData);
00525 llassert_always(data_offset <= mDataSize);
00526 memcpy(data, mReadData, data_offset);
00527 delete[] mReadData;
00528 mReadData = NULL;
00529 }
00530 llassert_always(mReadData == NULL);
00531 mReadData = data;
00532
00533 mBytesRead = -1;
00534 mBytesToRead = file_size;
00535 setPriority(LLWorkerThread::PRIORITY_LOW | mPriority);
00536 llassert_always(data_offset + mBytesToRead <= mDataSize);
00537 mFileHandle = LLLFSThread::sLocal->read(filename,
00538 mReadData + data_offset, file_offset, mBytesToRead,
00539 new ReadResponder(mCache, mRequestHandle));
00540 return false;
00541 }
00542 else
00543 {
00544 mDataSize = TEXTURE_CACHE_ENTRY_SIZE;
00545 return true;
00546 }
00547 }
00548 else
00549 {
00550 if (mBytesRead >= 0)
00551 {
00552 if (mBytesRead != mBytesToRead)
00553 {
00554 llwarns << "LLTextureCacheWorker: " << mID
00555 << " incorrect number of bytes read from body: " << mBytesRead
00556 << " != " << mBytesToRead << llendl;
00557 mDataSize = -1;
00558 }
00559 return true;
00560 }
00561 else
00562 {
00563 return false;
00564 }
00565 }
00566 #else
00567 std::string filename = mCache->getTextureFileName(mID);
00568 S32 filesize = ll_apr_file_size(filename, mCache->getFileAPRPool());
00569 S32 bytes_read = 0;
00570 if (filesize > mOffset)
00571 {
00572 S32 datasize = TEXTURE_CACHE_ENTRY_SIZE + filesize;
00573 mDataSize = llmin(datasize, mDataSize);
00574 S32 data_offset = TEXTURE_CACHE_ENTRY_SIZE - mOffset;
00575 data_offset = llmax(data_offset, 0);
00576 S32 file_size = mDataSize - data_offset;
00577 S32 file_offset = mOffset - TEXTURE_CACHE_ENTRY_SIZE;
00578 file_offset = llmax(file_offset, 0);
00579
00580 U8* data = new U8[mDataSize];
00581 if (data_offset > 0)
00582 {
00583 llassert_always(mReadData);
00584 memcpy(data, mReadData, data_offset);
00585 delete[] mReadData;
00586 }
00587 mReadData = data;
00588 bytes_read = ll_apr_file_read_ex(filename, mCache->getFileAPRPool(),
00589 mReadData + data_offset,
00590 file_offset, file_size);
00591 if (bytes_read != file_size)
00592 {
00593 llwarns << "LLTextureCacheWorker: " << mID
00594 << " incorrect number of bytes read from body: " << bytes_read
00595 << " / " << file_size << llendl;
00596 mDataSize = -1;
00597 return true;
00598 }
00599 }
00600 else
00601 {
00602 mDataSize = TEXTURE_CACHE_ENTRY_SIZE;
00603 }
00604
00605 return true;
00606 #endif
00607 }
00608
00609 return false;
00610 }
00611
00612 bool LLTextureCacheRemoteWorker::doWrite()
00613 {
00614 S32 idx = -1;
00615
00616
00617
00618 if (mState == INIT)
00619 {
00620 S32 cur_imagesize = 0;
00621 S32 offset = mOffset;
00622 idx = mCache->getHeaderCacheEntry(mID, false, &cur_imagesize);
00623 if (idx >= 0 && cur_imagesize > 0)
00624 {
00625 offset = TEXTURE_CACHE_ENTRY_SIZE;
00626 }
00627 idx = mCache->getHeaderCacheEntry(mID, true, &mImageSize);
00628 if (idx >= 0)
00629 {
00630 if(cur_imagesize > 0 && mImageSize != cur_imagesize)
00631 {
00632 llwarns << "Header cache entry size: " << cur_imagesize << " != mImageSize: " << mImageSize << llendl;
00633 offset = 0;
00634 }
00635 mState = offset < TEXTURE_CACHE_ENTRY_SIZE ? HEADER : BODY;
00636 }
00637 else
00638 {
00639 mDataSize = -1;
00640 return true;
00641 }
00642 }
00643
00644 if (mState == HEADER)
00645 {
00646 #if USE_LFS_WRITE
00647 if (mFileHandle == LLLFSThread::nullHandle())
00648 {
00649 llassert_always(idx >= 0);
00650 llassert_always(mOffset < TEXTURE_CACHE_ENTRY_SIZE);
00651 S32 offset = idx * TEXTURE_CACHE_ENTRY_SIZE + mOffset;
00652 S32 size = TEXTURE_CACHE_ENTRY_SIZE - mOffset;
00653 mBytesRead = -1;
00654 mBytesToRead = size;
00655 setPriority(LLWorkerThread::PRIORITY_LOW | mPriority);
00656 mFileHandle = LLLFSThread::sLocal->write(mCache->mHeaderDataFileName,
00657 mWriteData, offset, mBytesToRead,
00658 new WriteResponder(mCache, mRequestHandle));
00659 return false;
00660 }
00661 else
00662 {
00663 if (mBytesRead >= 0)
00664 {
00665 if (mBytesRead != mBytesToRead)
00666 {
00667 llwarns << "LLTextureCacheWorker: " << mID
00668 << " incorrect number of bytes written to header: " << mBytesRead
00669 << " != " << mBytesToRead << llendl;
00670 mDataSize = -1;
00671 return true;
00672 }
00673 if (mDataSize <= mBytesToRead)
00674 {
00675 return true;
00676 }
00677 else
00678 {
00679 mFileHandle = LLLFSThread::nullHandle();
00680 mState = BODY;
00681 }
00682 }
00683 else
00684 {
00685 return false;
00686 }
00687 }
00688 #else
00689 llassert_always(idx >= 0);
00690 llassert_always(mOffset < TEXTURE_CACHE_ENTRY_SIZE);
00691 S32 offset = idx * TEXTURE_CACHE_ENTRY_SIZE + mOffset;
00692 S32 size = TEXTURE_CACHE_ENTRY_SIZE - mOffset;
00693 S32 bytes_written = ll_apr_file_write_ex(mCache->mHeaderDataFileName, mCache->getFileAPRPool(),
00694 mWriteData, offset, size);
00695
00696 if (bytes_written <= 0)
00697 {
00698 llwarns << "LLTextureCacheWorker: missing entry: " << mID << llendl;
00699 mDataSize = -1;
00700 return true;
00701 }
00702
00703 if (mDataSize <= size)
00704 {
00705 return true;
00706 }
00707 else
00708 {
00709 mState = BODY;
00710 }
00711 #endif
00712 }
00713
00714 if (mState == BODY)
00715 {
00716 #if USE_LFS_WRITE
00717 if (mFileHandle == LLLFSThread::nullHandle())
00718 {
00719 S32 data_offset = TEXTURE_CACHE_ENTRY_SIZE - mOffset;
00720 data_offset = llmax(data_offset, 0);
00721 S32 file_size = mDataSize - data_offset;
00722 S32 file_offset = mOffset - TEXTURE_CACHE_ENTRY_SIZE;
00723 file_offset = llmax(file_offset, 0);
00724 if (file_size > 0 && mCache->appendToTextureEntryList(mID, file_size))
00725 {
00726 std::string filename = mCache->getTextureFileName(mID);
00727 mBytesRead = -1;
00728 mBytesToRead = file_size;
00729 setPriority(LLWorkerThread::PRIORITY_LOW | mPriority);
00730 mFileHandle = LLLFSThread::sLocal->write(filename,
00731 mWriteData + data_offset, file_offset, mBytesToRead,
00732 new WriteResponder(mCache, mRequestHandle));
00733 return false;
00734 }
00735 else
00736 {
00737 mDataSize = 0;
00738 return true;
00739 }
00740 }
00741 else
00742 {
00743 if (mBytesRead >= 0)
00744 {
00745 if (mBytesRead != mBytesToRead)
00746 {
00747 llwarns << "LLTextureCacheWorker: " << mID
00748 << " incorrect number of bytes written to body: " << mBytesRead
00749 << " != " << mBytesToRead << llendl;
00750 mDataSize = -1;
00751 }
00752 return true;
00753 }
00754 else
00755 {
00756 return false;
00757 }
00758 }
00759 #else
00760 S32 data_offset = TEXTURE_CACHE_ENTRY_SIZE - mOffset;
00761 data_offset = llmax(data_offset, 0);
00762 S32 file_size = mDataSize - data_offset;
00763 S32 file_offset = mOffset - TEXTURE_CACHE_ENTRY_SIZE;
00764 file_offset = llmax(file_offset, 0);
00765 S32 bytes_written = 0;
00766 if (file_size > 0 && mCache->appendToTextureEntryList(mID, file_size))
00767 {
00768 std::string filename = mCache->getTextureFileName(mID);
00769 bytes_written = ll_apr_file_write_ex(filename, mCache->getFileAPRPool(),
00770 mWriteData + data_offset,
00771 file_offset, file_size);
00772 if (bytes_written <= 0)
00773 {
00774 mDataSize = -1;
00775 }
00776 }
00777 else
00778 {
00779 mDataSize = 0;
00780 }
00781
00782 return true;
00783 #endif
00784 }
00785
00786 return false;
00787 }
00788
00789
00790 bool LLTextureCacheWorker::doWork(S32 param)
00791 {
00792 bool res = false;
00793 if (param == 0)
00794 {
00795 res = doRead();
00796 }
00797 else if (param == 1)
00798 {
00799 res = doWrite();
00800 }
00801 else
00802 {
00803 llassert_always(0);
00804 }
00805 return res;
00806 }
00807
00808
00809 void LLTextureCacheWorker::finishWork(S32 param, bool completed)
00810 {
00811 if (mResponder.notNull())
00812 {
00813 bool success = (completed && mDataSize > 0);
00814 if (param == 0)
00815 {
00816
00817 if (success)
00818 {
00819 mResponder->setData(mReadData, mDataSize, mImageSize, mImageFormat, mImageLocal);
00820 mReadData = NULL;
00821 mDataSize = 0;
00822 }
00823 else
00824 {
00825 delete[] mReadData;
00826 mReadData = NULL;
00827
00828 }
00829 }
00830 else
00831 {
00832
00833 mWriteData = NULL;
00834 mDataSize = 0;
00835 }
00836 mCache->addCompleted(mResponder, success);
00837 }
00838 }
00839
00840
00841 void LLTextureCacheWorker::endWork(S32 param, bool aborted)
00842 {
00843 if (aborted)
00844 {
00845
00846 return;
00847 }
00848 switch(param)
00849 {
00850 default:
00851 case 0:
00852 case 1:
00853 {
00854 if (mDataSize < 0)
00855 {
00856
00857 mCache->removeFromCache(mID);
00858 }
00859 break;
00860 }
00861 }
00862 }
00863
00865
00866 LLTextureCache::LLTextureCache(bool threaded)
00867 : LLWorkerThread("TextureCache", threaded),
00868 mWorkersMutex(getAPRPool()),
00869 mHeaderMutex(getAPRPool()),
00870 mListMutex(getAPRPool()),
00871 mFileAPRPool(NULL),
00872 mReadOnly(FALSE),
00873 mTexturesSizeTotal(0),
00874 mDoPurge(FALSE)
00875 {
00876 apr_pool_create(&mFileAPRPool, NULL);
00877 }
00878
00879 LLTextureCache::~LLTextureCache()
00880 {
00881 apr_pool_destroy(mFileAPRPool);
00882 }
00883
00885
00886
00887 S32 LLTextureCache::update(U32 max_time_ms)
00888 {
00889 S32 res;
00890 res = LLWorkerThread::update(max_time_ms);
00891
00892 mListMutex.lock();
00893 handle_list_t priorty_list = mPrioritizeWriteList;
00894 mPrioritizeWriteList.clear();
00895 responder_list_t completed_list = mCompletedList;
00896 mCompletedList.clear();
00897 mListMutex.unlock();
00898
00899 lockWorkers();
00900
00901 for (handle_list_t::iterator iter1 = priorty_list.begin();
00902 iter1 != priorty_list.end(); ++iter1)
00903 {
00904 handle_t handle = *iter1;
00905 handle_map_t::iterator iter2 = mWriters.find(handle);
00906 if(iter2 != mWriters.end())
00907 {
00908 LLTextureCacheWorker* worker = iter2->second;
00909 worker->setPriority(LLWorkerThread::PRIORITY_HIGH | worker->mPriority);
00910 }
00911 }
00912
00913 for (responder_list_t::iterator iter1 = completed_list.begin();
00914 iter1 != completed_list.end(); ++iter1)
00915 {
00916 Responder *responder = iter1->first;
00917 bool success = iter1->second;
00918 responder->completed(success);
00919 }
00920
00921 unlockWorkers();
00922
00923 return res;
00924 }
00925
00927
00928 std::string LLTextureCache::getLocalFileName(const LLUUID& id)
00929 {
00930
00931 std::string idstr = id.asString();
00932 std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_SKINS, "textures", idstr);
00933 return filename;
00934 }
00935
00936 std::string LLTextureCache::getTextureFileName(const LLUUID& id)
00937 {
00938 std::string idstr = id.asString();
00939 std::string delem = gDirUtilp->getDirDelimiter();
00940 std::string filename = mTexturesDirName + delem + idstr[0] + delem + idstr;
00941 return filename;
00942 }
00943
00944 bool LLTextureCache::appendToTextureEntryList(const LLUUID& id, S32 bodysize)
00945 {
00946 bool res = false;
00947 bool purge = false;
00948
00949 {
00950 LLMutexLock lock(&mHeaderMutex);
00951 size_map_t::iterator iter = mTexturesSizeMap.find(id);
00952 if (iter == mTexturesSizeMap.end() || iter->second < bodysize)
00953 {
00954 llassert_always(bodysize > 0);
00955 Entry* entry = new Entry(id, bodysize, time(NULL));
00956 ll_apr_file_write_ex(mTexturesDirEntriesFileName, getFileAPRPool(),
00957 (U8*)entry, -1, 1*sizeof(Entry));
00958 delete entry;
00959 if (iter != mTexturesSizeMap.end())
00960 {
00961 mTexturesSizeTotal -= iter->second;
00962 }
00963 mTexturesSizeTotal += bodysize;
00964 mTexturesSizeMap[id] = bodysize;
00965 if (mTexturesSizeTotal > sCacheMaxTexturesSize)
00966 {
00967 purge = true;
00968 }
00969 res = true;
00970 }
00971 }
00972 if (purge)
00973 {
00974 mDoPurge = TRUE;
00975 }
00976 return res;
00977 }
00978
00980
00981
00982 const S32 MAX_REASONABLE_FILE_SIZE = 512*1024*1024;
00983 F32 LLTextureCache::sHeaderCacheVersion = 1.0f;
00984 U32 LLTextureCache::sCacheMaxEntries = MAX_REASONABLE_FILE_SIZE / TEXTURE_CACHE_ENTRY_SIZE;
00985 S64 LLTextureCache::sCacheMaxTexturesSize = 0;
00986 const char* entries_filename = "texture.entries";
00987 const char* cache_filename = "texture.cache";
00988 const char* textures_dirname = "textures";
00989
00990 void LLTextureCache::setDirNames(ELLPath location)
00991 {
00992 std::string delem = gDirUtilp->getDirDelimiter();
00993 mHeaderEntriesFileName = gDirUtilp->getExpandedFilename(location, entries_filename);
00994 mHeaderDataFileName = gDirUtilp->getExpandedFilename(location, cache_filename);
00995 mTexturesDirName = gDirUtilp->getExpandedFilename(location, textures_dirname);
00996 mTexturesDirEntriesFileName = mTexturesDirName + delem + entries_filename;
00997 }
00998
00999 void LLTextureCache::purgeCache(ELLPath location)
01000 {
01001 if (!mReadOnly)
01002 {
01003 setDirNames(location);
01004
01005 ll_apr_file_remove(mHeaderEntriesFileName, NULL);
01006 ll_apr_file_remove(mHeaderDataFileName, NULL);
01007 }
01008 purgeAllTextures(true);
01009 }
01010
01011 S64 LLTextureCache::initCache(ELLPath location, S64 max_size, BOOL read_only)
01012 {
01013 mReadOnly = read_only;
01014
01015 S64 header_size = (max_size * 2) / 10;
01016 S64 max_entries = header_size / TEXTURE_CACHE_ENTRY_SIZE;
01017 sCacheMaxEntries = (S32)(llmin((S64)sCacheMaxEntries, max_entries));
01018 header_size = sCacheMaxEntries * TEXTURE_CACHE_ENTRY_SIZE;
01019 max_size -= header_size;
01020 if (sCacheMaxTexturesSize > 0)
01021 sCacheMaxTexturesSize = llmin(sCacheMaxTexturesSize, max_size);
01022 else
01023 sCacheMaxTexturesSize = max_size;
01024 max_size -= sCacheMaxTexturesSize;
01025
01026 LL_INFOS("TextureCache") << "Headers: " << sCacheMaxEntries
01027 << " Textures size: " << sCacheMaxTexturesSize/(1024*1024) << " MB" << LL_ENDL;
01028
01029 setDirNames(location);
01030
01031 if (!mReadOnly)
01032 {
01033 LLFile::mkdir(mTexturesDirName.c_str());
01034 const char* subdirs = "0123456789abcdef";
01035 for (S32 i=0; i<16; i++)
01036 {
01037 std::string dirname = mTexturesDirName + gDirUtilp->getDirDelimiter() + subdirs[i];
01038 LLFile::mkdir(dirname.c_str());
01039 }
01040 }
01041 readHeaderCache();
01042 purgeTextures(true);
01043
01044 return max_size;
01045 }
01046
01047 struct lru_data
01048 {
01049 lru_data(U32 t, S32 i, const LLUUID& id) { time=t; index=i; uuid=id; }
01050 U32 time;
01051 S32 index;
01052 LLUUID uuid;
01053 struct Compare
01054 {
01055
01056 typedef const lru_data* lru_data_ptr;
01057 bool operator()(const lru_data_ptr& a, const lru_data_ptr& b) const
01058 {
01059 if (a->time > b->time)
01060 return true;
01061 else if (b->time > a->time)
01062 return false;
01063 else
01064 return a->index < b->index;
01065 }
01066 };
01067 };
01068
01069
01070 void LLTextureCache::readHeaderCache(apr_pool_t* poolp)
01071 {
01072 LLMutexLock lock(&mHeaderMutex);
01073 mHeaderEntriesInfo.mVersion = 0.f;
01074 mHeaderEntriesInfo.mEntries = 0;
01075 if (ll_apr_file_exists(mHeaderEntriesFileName, poolp))
01076 {
01077 ll_apr_file_read_ex(mHeaderEntriesFileName, poolp,
01078 (U8*)&mHeaderEntriesInfo, 0, sizeof(EntriesInfo));
01079 }
01080 if (mHeaderEntriesInfo.mVersion != sHeaderCacheVersion)
01081 {
01082 if (!mReadOnly)
01083 {
01084
01085 mHeaderEntriesInfo.mVersion = sHeaderCacheVersion;
01086 ll_apr_file_write_ex(mHeaderEntriesFileName, poolp,
01087 (U8*)&mHeaderEntriesInfo, 0, sizeof(EntriesInfo));
01088 }
01089 }
01090 else
01091 {
01092 S32 num_entries = mHeaderEntriesInfo.mEntries;
01093 if (num_entries)
01094 {
01095 Entry* entries = new Entry[num_entries];
01096 ll_apr_file_read_ex(mHeaderEntriesFileName, poolp,
01097 (U8*)entries, sizeof(EntriesInfo), num_entries*sizeof(Entry));
01098 typedef std::set<lru_data*, lru_data::Compare> lru_set_t;
01099 lru_set_t lru;
01100 for (S32 i=0; i<num_entries; i++)
01101 {
01102 if (entries[i].mSize >= 0)
01103 {
01104 const LLUUID& id = entries[i].mID;
01105 lru.insert(new lru_data(entries[i].mTime, i, id));
01106 mHeaderIDMap[id] = i;
01107 }
01108 }
01109 mLRU.clear();
01110 S32 lru_entries = sCacheMaxEntries / 10;
01111 for (lru_set_t::iterator iter = lru.begin(); iter != lru.end(); ++iter)
01112 {
01113 lru_data* data = *iter;
01114 mLRU[data->index] = data->uuid;
01115 if (--lru_entries <= 0)
01116 break;
01117 }
01118 for_each(lru.begin(), lru.end(), DeletePointer());
01119 delete[] entries;
01120 }
01121 }
01122 }
01123
01125
01126 void LLTextureCache::purgeAllTextures(bool purge_directories)
01127 {
01128 if (!mReadOnly)
01129 {
01130 const char* subdirs = "0123456789abcdef";
01131 std::string delem = gDirUtilp->getDirDelimiter();
01132 std::string mask = delem + "*";
01133 for (S32 i=0; i<16; i++)
01134 {
01135 std::string dirname = mTexturesDirName + delem + subdirs[i];
01136 gDirUtilp->deleteFilesInDir(dirname.c_str(),mask);
01137 if (purge_directories)
01138 {
01139 LLFile::rmdir(dirname.c_str());
01140 }
01141 }
01142 ll_apr_file_remove(mTexturesDirEntriesFileName, NULL);
01143 if (purge_directories)
01144 {
01145 LLFile::rmdir(mTexturesDirName.c_str());
01146 }
01147 }
01148 mTexturesSizeMap.clear();
01149 }
01150
01151 void LLTextureCache::purgeTextures(bool validate)
01152 {
01153 if (mReadOnly)
01154 {
01155 return;
01156 }
01157
01158 LLMutexLock lock(&mHeaderMutex);
01159
01160 S32 filesize = ll_apr_file_size(mTexturesDirEntriesFileName, NULL);
01161 S32 num_entries = filesize / sizeof(Entry);
01162 if (num_entries * (S32)sizeof(Entry) != filesize)
01163 {
01164 LL_WARNS("TextureCache") << "Bad cache file: " << mTexturesDirEntriesFileName << " Purging." << LL_ENDL;
01165 purgeAllTextures(false);
01166 return;
01167 }
01168 if (num_entries == 0)
01169 {
01170 return;
01171 }
01172
01173 Entry* entries = new Entry[num_entries];
01174 S32 bytes_read = ll_apr_file_read_ex(mTexturesDirEntriesFileName, NULL,
01175 (U8*)entries, 0, num_entries*sizeof(Entry));
01176 if (bytes_read != filesize)
01177 {
01178 LL_WARNS("TextureCache") << "Bad cache file (2): " << mTexturesDirEntriesFileName << " Purging." << LL_ENDL;
01179 purgeAllTextures(false);
01180 return;
01181 }
01182
01183 LL_DEBUGS("TextureCache") << "TEXTURE CACHE: Reading Entries..." << LL_ENDL;
01184
01185 std::map<LLUUID, S32> entry_idx_map;
01186 S64 total_size = 0;
01187 for (S32 idx=0; idx<num_entries; idx++)
01188 {
01189 const LLUUID& id = entries[idx].mID;
01190 LL_DEBUGS("TextureCache") << "Entry: " << id << " Size: " << entries[idx].mSize << " Time: " << entries[idx].mTime << LL_ENDL;
01191 std::map<LLUUID, S32>::iterator iter = entry_idx_map.find(id);
01192 if (iter != entry_idx_map.end())
01193 {
01194
01195 S32 pidx = iter->second;
01196 total_size -= entries[pidx].mSize;
01197 entries[pidx].mSize = 0;
01198 }
01199 entry_idx_map[id] = idx;
01200 total_size += entries[idx].mSize;
01201 }
01202
01203 U32 validate_idx = 0;
01204 if (validate)
01205 {
01206 validate_idx = gSavedSettings.getU32("CacheValidateCounter");
01207 U32 next_idx = (++validate_idx) % 256;
01208 gSavedSettings.setU32("CacheValidateCounter", next_idx);
01209 LL_DEBUGS("TextureCache") << "TEXTURE CACHE: Validating: " << validate_idx << LL_ENDL;
01210 }
01211
01212 S64 min_cache_size = (sCacheMaxTexturesSize * 9) / 10;
01213 S32 purge_count = 0;
01214 S32 next_idx = 0;
01215 for (S32 idx=0; idx<num_entries; idx++)
01216 {
01217 if (entries[idx].mSize == 0)
01218 {
01219 continue;
01220 }
01221 bool purge_entry = false;
01222 std::string filename = getTextureFileName(entries[idx].mID);
01223 if (total_size >= min_cache_size)
01224 {
01225 purge_entry = true;
01226 }
01227 else if (validate)
01228 {
01229
01230 S32 uuididx = entries[idx].mID.mData[0];
01231 if (uuididx == validate_idx)
01232 {
01233 LL_DEBUGS("TextureCache") << "Validating: " << filename << "Size: " << entries[idx].mSize << LL_ENDL;
01234 S32 bodysize = ll_apr_file_size(filename, NULL);
01235 if (bodysize != entries[idx].mSize)
01236 {
01237 LL_WARNS("TextureCache") << "TEXTURE CACHE BODY HAS BAD SIZE: " << bodysize << " != " << entries[idx].mSize
01238 << filename << LL_ENDL;
01239 purge_entry = true;
01240 }
01241 }
01242 }
01243 if (purge_entry)
01244 {
01245 purge_count++;
01246 LL_DEBUGS("TextureCache") << "PURGING: " << filename << LL_ENDL;
01247 ll_apr_file_remove(filename, NULL);
01248 total_size -= entries[idx].mSize;
01249 entries[idx].mSize = 0;
01250 }
01251 else
01252 {
01253 if (next_idx != idx)
01254 {
01255 entries[next_idx] = entries[idx];
01256 }
01257 ++next_idx;
01258 }
01259 }
01260 num_entries = next_idx;
01261
01262 LL_DEBUGS("TextureCache") << "TEXTURE CACHE: Writing Entries: " << num_entries << LL_ENDL;
01263
01264 ll_apr_file_remove(mTexturesDirEntriesFileName, NULL);
01265 ll_apr_file_write_ex(mTexturesDirEntriesFileName, NULL,
01266 (U8*)&entries[0], 0, num_entries*sizeof(Entry));
01267
01268 mTexturesSizeTotal = 0;
01269 mTexturesSizeMap.clear();
01270 for (S32 idx=0; idx<num_entries; idx++)
01271 {
01272 mTexturesSizeMap[entries[idx].mID] = entries[idx].mSize;
01273 mTexturesSizeTotal += entries[idx].mSize;
01274 }
01275 llassert(mTexturesSizeTotal == total_size);
01276
01277 delete[] entries;
01278
01279 LL_INFOS("TextureCache") << "TEXTURE CACHE:"
01280 << " PURGED: " << purge_count
01281 << " ENTRIES: " << num_entries
01282 << " CACHE SIZE: " << total_size / 1024*1024 << " MB"
01283 << llendl;
01284 }
01285
01287
01288
01289 LLTextureCacheWorker* LLTextureCache::getReader(handle_t handle)
01290 {
01291 LLTextureCacheWorker* res = NULL;
01292 handle_map_t::iterator iter = mReaders.find(handle);
01293 if (iter != mReaders.end())
01294 {
01295 res = iter->second;
01296 }
01297 return res;
01298 }
01299
01300 LLTextureCacheWorker* LLTextureCache::getWriter(handle_t handle)
01301 {
01302 LLTextureCacheWorker* res = NULL;
01303 handle_map_t::iterator iter = mWriters.find(handle);
01304 if (iter != mWriters.end())
01305 {
01306 res = iter->second;
01307 }
01308 return res;
01309 }
01310
01312
01313
01314 S32 LLTextureCache::getHeaderCacheEntry(const LLUUID& id, bool touch, S32* imagesize)
01315 {
01316 bool retry = false;
01317 S32 idx = -1;
01318
01319 {
01320 LLMutexLock lock(&mHeaderMutex);
01321 id_map_t::iterator iter = mHeaderIDMap.find(id);
01322 if (iter != mHeaderIDMap.end())
01323 {
01324 idx = iter->second;
01325 }
01326 else if (touch && !mReadOnly)
01327 {
01328 if (mHeaderEntriesInfo.mEntries < sCacheMaxEntries)
01329 {
01330
01331 idx = mHeaderEntriesInfo.mEntries++;
01332 mHeaderIDMap[id] = idx;
01333
01334 ll_apr_file_write_ex(mHeaderEntriesFileName, getFileAPRPool(),
01335 (U8*)&mHeaderEntriesInfo, 0, sizeof(EntriesInfo));
01336 }
01337 else if (!mLRU.empty())
01338 {
01339 idx = mLRU.begin()->first;
01340 const LLUUID& oldid = mLRU.begin()->second;
01341 mHeaderIDMap.erase(oldid);
01342 mTexturesSizeMap.erase(oldid);
01343 mHeaderIDMap[id] = idx;
01344 }
01345 else
01346 {
01347 idx = -1;
01348 retry = true;
01349 }
01350 }
01351 if (idx >= 0)
01352 {
01353 if (touch && !mReadOnly)
01354 {
01355
01356 mLRU.erase(idx);
01357 llassert_always(imagesize && *imagesize > 0);
01358 Entry* entry = new Entry(id, *imagesize, time(NULL));
01359 S32 offset = sizeof(EntriesInfo) + idx * sizeof(Entry);
01360 ll_apr_file_write_ex(mHeaderEntriesFileName, getFileAPRPool(),
01361 (U8*)entry, offset, sizeof(Entry));
01362 delete entry;
01363 }
01364 else if (imagesize)
01365 {
01366
01367 Entry entry;
01368 S32 offset = sizeof(EntriesInfo) + idx * sizeof(Entry);
01369 ll_apr_file_read_ex(mHeaderEntriesFileName, getFileAPRPool(),
01370 (U8*)&entry, offset, sizeof(Entry));
01371 *imagesize = entry.mSize;
01372 }
01373 }
01374 }
01375 if (retry)
01376 {
01377 readHeaderCache(getFileAPRPool());
01378 llassert_always(!mLRU.empty() || mHeaderEntriesInfo.mEntries < sCacheMaxEntries);
01379 idx = getHeaderCacheEntry(id, touch, imagesize);
01380 }
01381 return idx;
01382 }
01383
01385
01386
01387
01388 LLTextureCache::handle_t LLTextureCache::readFromCache(const LLString& filename, const LLUUID& id, U32 priority,
01389 S32 offset, S32 size, ReadResponder* responder)
01390 {
01391
01392
01393 LLMutexLock lock(&mWorkersMutex);
01394 LLTextureCacheWorker* worker = new LLTextureCacheLocalFileWorker(this, priority, filename, id,
01395 NULL, size, offset, 0,
01396 responder);
01397 handle_t handle = worker->read();
01398 mReaders[handle] = worker;
01399 return handle;
01400 }
01401
01402 LLTextureCache::handle_t LLTextureCache::readFromCache(const LLUUID& id, U32 priority,
01403 S32 offset, S32 size, ReadResponder* responder)
01404 {
01405
01406
01407 LLMutexLock lock(&mWorkersMutex);
01408 LLTextureCacheWorker* worker = new LLTextureCacheRemoteWorker(this, priority, id,
01409 NULL, size, offset, 0,
01410 responder);
01411 handle_t handle = worker->read();
01412 mReaders[handle] = worker;
01413 return handle;
01414 }
01415
01416
01417 bool LLTextureCache::readComplete(handle_t handle, bool abort)
01418 {
01419 lockWorkers();
01420 handle_map_t::iterator iter = mReaders.find(handle);
01421 llassert_always(iter != mReaders.end());
01422 LLTextureCacheWorker* worker = iter->second;
01423 bool res = worker->complete();
01424 if (res || abort)
01425 {
01426 mReaders.erase(handle);
01427 unlockWorkers();
01428 worker->scheduleDelete();
01429 return true;
01430 }
01431 else
01432 {
01433 unlockWorkers();
01434 return false;
01435 }
01436 }
01437
01438 LLTextureCache::handle_t LLTextureCache::writeToCache(const LLUUID& id, U32 priority,
01439 U8* data, S32 datasize, S32 imagesize,
01440 WriteResponder* responder)
01441 {
01442 if (mReadOnly)
01443 {
01444 delete responder;
01445 return LLWorkerThread::nullHandle();
01446 }
01447 if (mDoPurge)
01448 {
01449
01450
01451
01452 purgeTextures(false);
01453 mDoPurge = FALSE;
01454 }
01455 if (datasize >= TEXTURE_CACHE_ENTRY_SIZE)
01456 {
01457 LLMutexLock lock(&mWorkersMutex);
01458 llassert_always(imagesize > 0);
01459 LLTextureCacheWorker* worker = new LLTextureCacheRemoteWorker(this, priority, id,
01460 data, datasize, 0,
01461 imagesize, responder);
01462 handle_t handle = worker->write();
01463 mWriters[handle] = worker;
01464 return handle;
01465 }
01466 delete responder;
01467 return LLWorkerThread::nullHandle();
01468 }
01469
01470 bool LLTextureCache::writeComplete(handle_t handle, bool abort)
01471 {
01472 lockWorkers();
01473 handle_map_t::iterator iter = mWriters.find(handle);
01474 llassert_always(iter != mWriters.end());
01475 LLTextureCacheWorker* worker = iter->second;
01476 if (worker->complete() || abort)
01477 {
01478 mWriters.erase(handle);
01479 unlockWorkers();
01480 worker->scheduleDelete();
01481 return true;
01482 }
01483 else
01484 {
01485 unlockWorkers();
01486 return false;
01487 }
01488 }
01489
01490 void LLTextureCache::prioritizeWrite(handle_t handle)
01491 {
01492
01493
01494 LLMutexLock lock(&mListMutex);
01495 mPrioritizeWriteList.push_back(handle);
01496 }
01497
01498 void LLTextureCache::addCompleted(Responder* responder, bool success)
01499 {
01500 LLMutexLock lock(&mListMutex);
01501 mCompletedList.push_back(std::make_pair(responder,success));
01502 }
01503
01505
01506
01507
01508 bool LLTextureCache::removeHeaderCacheEntry(const LLUUID& id)
01509 {
01510 if (mReadOnly)
01511 {
01512 return false;
01513 }
01514 LLMutexLock lock(&mHeaderMutex);
01515 id_map_t::iterator iter = mHeaderIDMap.find(id);
01516 if (iter != mHeaderIDMap.end())
01517 {
01518 S32 idx = iter->second;
01519 if (idx >= 0)
01520 {
01521 Entry* entry = new Entry(id, -1, time(NULL));
01522 S32 offset = sizeof(EntriesInfo) + idx * sizeof(Entry);
01523 ll_apr_file_write_ex(mHeaderEntriesFileName, NULL,
01524 (U8*)entry, offset, sizeof(Entry));
01525 delete entry;
01526 mLRU[idx] = id;
01527 mHeaderIDMap.erase(id);
01528 mTexturesSizeMap.erase(id);
01529 return true;
01530 }
01531 }
01532 return false;
01533 }
01534
01535 void LLTextureCache::removeFromCache(const LLUUID& id)
01536 {
01537 llwarns << "Removing texture from cache: " << id << llendl;
01538 if (!mReadOnly)
01539 {
01540 removeHeaderCacheEntry(id);
01541 ll_apr_file_remove(getTextureFileName(id), NULL);
01542 }
01543 }
01544
01546
01547 LLTextureCache::ReadResponder::ReadResponder()
01548 : mImageSize(0),
01549 mImageLocal(FALSE)
01550 {
01551 }
01552
01553 void LLTextureCache::ReadResponder::setData(U8* data, S32 datasize, S32 imagesize, S32 imageformat, BOOL imagelocal)
01554 {
01555 if (mFormattedImage.notNull())
01556 {
01557 llassert_always(mFormattedImage->getCodec() == imageformat);
01558 mFormattedImage->appendData(data, datasize);
01559 }
01560 else
01561 {
01562 mFormattedImage = LLImageFormatted::createFromType(imageformat);
01563 mFormattedImage->setData(data,datasize);
01564 }
01565 mImageSize = imagesize;
01566 mImageLocal = imagelocal;
01567 }
01568