aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/newview/lltexturecache.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'linden/indra/newview/lltexturecache.cpp')
-rw-r--r--linden/indra/newview/lltexturecache.cpp1268
1 files changed, 626 insertions, 642 deletions
diff --git a/linden/indra/newview/lltexturecache.cpp b/linden/indra/newview/lltexturecache.cpp
index 9c3bed2..e0bef61 100644
--- a/linden/indra/newview/lltexturecache.cpp
+++ b/linden/indra/newview/lltexturecache.cpp
@@ -43,11 +43,18 @@
43// Included to allow LLTextureCache::purgeTextures() to pause watchdog timeout 43// Included to allow LLTextureCache::purgeTextures() to pause watchdog timeout
44#include "llappviewer.h" 44#include "llappviewer.h"
45 45
46#define USE_LFS_READ 0 46// Cache organization:
47#define USE_LFS_WRITE 0 47// cache/texture.entries
48 48// Unordered array of Entry structs
49// Note: first 4 bytes store file size, rest is j2c data 49// cache/texture.cache
50const S32 TEXTURE_CACHE_ENTRY_SIZE = FIRST_PACKET_SIZE; //1024; 50// First TEXTURE_CACHE_ENTRY_SIZE bytes of each texture in texture.entries in same order
51// Entry size same as header packet, so we're not 0-padding unless whole image is contained in header.
52// cache/textures/[0-F]/UUID.texture
53// Actual texture body files
54
55const S32 TEXTURE_CACHE_ENTRY_SIZE = FIRST_PACKET_SIZE;
56const F32 TEXTURE_CACHE_PURGE_AMOUNT = .20f; // % amount to reduce the cache by when it exceeds its limit
57const F32 TEXTURE_CACHE_LRU_SIZE = .10f; // % amount for LRU list (low overhead to regenerate)
51 58
52class LLTextureCacheWorker : public LLWorkerClass 59class LLTextureCacheWorker : public LLWorkerClass
53{ 60{
@@ -309,93 +316,74 @@ void LLTextureCacheWorker::startWork(S32 param)
309{ 316{
310} 317}
311 318
319// This is where a texture is read from the cache system (header and body)
320// Current assumption are:
321// - the whole data are in a raw form, will be stored at mReadData
322// - the size of this raw data is mDataSize and can be smaller than TEXTURE_CACHE_ENTRY_SIZE (the size of a record in the header cache)
323// - the code supports offset reading but this is actually never exercised in the viewer
312bool LLTextureCacheRemoteWorker::doRead() 324bool LLTextureCacheRemoteWorker::doRead()
313{ 325{
326 bool done = false;
327 S32 idx = -1;
328
314 S32 local_size = 0; 329 S32 local_size = 0;
315 std::string local_filename; 330 std::string local_filename;
316 331
332 // First state / stage : find out if the file is local
317 if (mState == INIT) 333 if (mState == INIT)
318 { 334 {
319 std::string filename = mCache->getLocalFileName(mID); 335 std::string filename = mCache->getLocalFileName(mID);
320 local_filename = filename + ".j2c"; 336 // Is it a JPEG2000 file?
321 local_size = LLAPRFile::size(local_filename);
322 if (local_size == 0)
323 { 337 {
324 local_filename = filename + ".tga"; 338 local_filename = filename + ".j2c";
325 local_size = LLAPRFile::size(local_filename); 339 local_size = LLAPRFile::size(local_filename);
326 if (local_size > 0) 340 if (local_size > 0)
327 { 341 {
328 mImageFormat = IMG_CODEC_TGA; 342 mImageFormat = IMG_CODEC_J2C;
329 mDataSize = local_size; // Only a complete .tga file is valid
330 } 343 }
331 } 344 }
332 if (local_size > 0) 345 // If not, is it a jpeg file?
333 { 346 if (local_size == 0)
334 mState = LOCAL;
335 }
336 else
337 {
338 mState = CACHE;
339 }
340 }
341
342 if (mState == LOCAL)
343 {
344#if USE_LFS_READ
345 if (mFileHandle == LLLFSThread::nullHandle())
346 { 347 {
347 mImageLocal = TRUE; 348 local_filename = filename + ".jpg";
348 mImageSize = local_size; 349 local_size = LLAPRFile::size(local_filename);
349 if (!mDataSize || mDataSize + mOffset > local_size) 350 if (local_size > 0)
350 {
351 mDataSize = local_size - mOffset;
352 }
353 if (mDataSize <= 0)
354 { 351 {
355 // no more data to read 352 mImageFormat = IMG_CODEC_JPEG;
356 mDataSize = 0; 353 mDataSize = local_size; // Only a complete .jpg file is valid
357 return true;
358 } 354 }
359 mReadData = new U8[mDataSize];
360 mBytesRead = -1;
361 mBytesToRead = mDataSize;
362 setPriority(LLWorkerThread::PRIORITY_LOW | mPriority);
363 mFileHandle = LLLFSThread::sLocal->read(local_filename, mReadData, mOffset, mDataSize,
364 new ReadResponder(mCache, mRequestHandle));
365 return false;
366 } 355 }
367 else 356 // Hmm... What about a targa file? (used for UI texture mostly)
357 if (local_size == 0)
368 { 358 {
369 if (mBytesRead >= 0) 359 local_filename = filename + ".tga";
370 { 360 local_size = LLAPRFile::size(local_filename);
371 if (mBytesRead != mBytesToRead) 361 if (local_size > 0)
372 {
373// llwarns << "Error reading file from local cache: " << local_filename
374// << " Bytes: " << mDataSize << " Offset: " << mOffset
375// << " / " << mDataSize << llendl;
376 mDataSize = 0; // failed
377 delete[] mReadData;
378 mReadData = NULL;
379 }
380 return true;
381 }
382 else
383 { 362 {
384 return false; 363 mImageFormat = IMG_CODEC_TGA;
364 mDataSize = local_size; // Only a complete .tga file is valid
385 } 365 }
386 } 366 }
387#else 367 // Determine the next stage: if we found a file, then LOCAL else CACHE
368 mState = (local_size > 0 ? LOCAL : CACHE);
369 }
370
371 // Second state / stage : if the file is local, load it and leave
372 if (!done && (mState == LOCAL))
373 {
374 llassert(local_size != 0); // we're assuming there is a non empty local file here...
388 if (!mDataSize || mDataSize > local_size) 375 if (!mDataSize || mDataSize > local_size)
389 { 376 {
390 mDataSize = local_size; 377 mDataSize = local_size;
391 } 378 }
379 // Allocate read buffer
392 mReadData = new U8[mDataSize]; 380 mReadData = new U8[mDataSize];
393 S32 bytes_read = LLAPRFile::readEx(local_filename, mReadData, mOffset, mDataSize); 381 S32 bytes_read = LLAPRFile::readEx(local_filename, mReadData, mOffset, mDataSize);
394 if (bytes_read != mDataSize) 382 if (bytes_read != mDataSize)
395 { 383 {
396// llwarns << "Error reading file from local cache: " << local_filename 384 llwarns << "Error reading file from local cache: " << local_filename
397// << " Bytes: " << mDataSize << " Offset: " << mOffset 385 << " Bytes: " << mDataSize << " Offset: " << mOffset
398// << " / " << mDataSize << llendl; 386 << " / " << mDataSize << llendl;
399 mDataSize = 0; 387 mDataSize = 0;
400 delete[] mReadData; 388 delete[] mReadData;
401 mReadData = NULL; 389 mReadData = NULL;
@@ -405,403 +393,273 @@ bool LLTextureCacheRemoteWorker::doRead()
405 mImageSize = local_size; 393 mImageSize = local_size;
406 mImageLocal = TRUE; 394 mImageLocal = TRUE;
407 } 395 }
408 return true; 396 // We're done...
409#endif 397 done = true;
410 } 398 }
411 399
412 S32 idx = -1; 400 // Second state / stage : identify the cache or not...
413 401 if (!done && (mState == CACHE))
414 if (mState == CACHE)
415 { 402 {
416 llassert_always(mImageSize == 0); 403 idx = mCache->getHeaderCacheEntry(mID, mImageSize);
417 idx = mCache->getHeaderCacheEntry(mID, false, &mImageSize); 404 if (idx < 0)
418 if (idx >= 0 && mImageSize > mOffset)
419 { 405 {
420 llassert_always(mImageSize > 0); 406 // The texture is *not* cached. We're done here...
421 if (!mDataSize || mDataSize > mImageSize) 407 mDataSize = 0; // no data
422 { 408 done = true;
423 mDataSize = mImageSize;
424 }
425 mState = mOffset < TEXTURE_CACHE_ENTRY_SIZE ? HEADER : BODY;
426 } 409 }
427 else 410 else
428 { 411 {
429 mDataSize = 0; // no data 412 // If the read offset is bigger than the header cache, we read directly from the body
430 return true; 413 // Note that currently, we *never* read with offset from the cache, so the result is *always* HEADER
414 mState = mOffset < TEXTURE_CACHE_ENTRY_SIZE ? HEADER : BODY;
431 } 415 }
432 } 416 }
433 417
434 if (mState == HEADER) 418 // Third state / stage : read data from the header cache (texture.entries) file
419 if (!done && (mState == HEADER))
435 { 420 {
436#if USE_LFS_READ 421 llassert_always(idx >= 0); // we need an entry here or reading the header makes no sense
437 if (mFileHandle == LLLFSThread::nullHandle())
438 {
439 llassert_always(idx >= 0);
440 llassert_always(mOffset < TEXTURE_CACHE_ENTRY_SIZE);
441 S32 offset = idx * TEXTURE_CACHE_ENTRY_SIZE + mOffset;
442 S32 size = TEXTURE_CACHE_ENTRY_SIZE - mOffset;
443 llassert_always(mReadData == NULL);
444 mReadData = new U8[size];
445 mBytesRead = -1;
446 mBytesToRead = size;
447 setPriority(LLWorkerThread::PRIORITY_LOW | mPriority);
448 mFileHandle = LLLFSThread::sLocal->read(mCache->mHeaderDataFileName,
449 mReadData, offset, mBytesToRead,
450 new ReadResponder(mCache, mRequestHandle));
451 return false;
452 }
453 else
454 {
455 if (mBytesRead >= 0)
456 {
457 if (mBytesRead != mBytesToRead)
458 {
459// llwarns << "LLTextureCacheWorker: " << mID
460// << " incorrect number of bytes read from header: " << mBytesRead
461// << " != " << mBytesToRead << llendl;
462 mDataSize = -1; // failed
463 return true;
464 }
465 if (mDataSize <= TEXTURE_CACHE_ENTRY_SIZE)
466 {
467 return true; // done
468 }
469 else
470 {
471 mFileHandle = LLLFSThread::nullHandle();
472 mState = BODY;
473 }
474 }
475 else
476 {
477 return false;
478 }
479 }
480#else
481 llassert_always(idx >= 0);
482 llassert_always(mOffset < TEXTURE_CACHE_ENTRY_SIZE); 422 llassert_always(mOffset < TEXTURE_CACHE_ENTRY_SIZE);
483 S32 offset = idx * TEXTURE_CACHE_ENTRY_SIZE + mOffset; 423 S32 offset = idx * TEXTURE_CACHE_ENTRY_SIZE + mOffset;
424 // Compute the size we need to read (in bytes)
484 S32 size = TEXTURE_CACHE_ENTRY_SIZE - mOffset; 425 S32 size = TEXTURE_CACHE_ENTRY_SIZE - mOffset;
426 size = llmin(size, mDataSize);
427 // Allocate the read buffer
485 mReadData = new U8[size]; 428 mReadData = new U8[size];
486 S32 bytes_read = LLAPRFile::readEx(mCache->mHeaderDataFileName, 429 S32 bytes_read = LLAPRFile::readEx(mCache->mHeaderDataFileName,
487 mReadData, offset, size); 430 mReadData, offset, size);
488 if (bytes_read != size) 431 if (bytes_read != size)
489 { 432 {
490// llwarns << "LLTextureCacheWorker: " << mID 433 llwarns << "LLTextureCacheWorker: " << mID
491// << " incorrect number of bytes read from header: " << bytes_read 434 << " incorrect number of bytes read from header: " << bytes_read
492// << " / " << size << llendl; 435 << " / " << size << llendl;
436 delete[] mReadData;
437 mReadData = NULL;
493 mDataSize = -1; // failed 438 mDataSize = -1; // failed
494 return true; 439 done = true;
495 } 440 }
496 if (mDataSize <= TEXTURE_CACHE_ENTRY_SIZE) 441 // If we already read all we expected, we're actually done
442 if (mDataSize <= bytes_read)
497 { 443 {
498 return true; // done 444 done = true;
499 } 445 }
500 else 446 else
501 { 447 {
502 mState = BODY; 448 mState = BODY;
503 } 449 }
504#endif
505 } 450 }
506 451
507 if (mState == BODY) 452 // Fourth state / stage : read the rest of the data from the UUID based cached file
453 if (!done && (mState == BODY))
508 { 454 {
509#if USE_LFS_READ
510 if (mFileHandle == LLLFSThread::nullHandle())
511 {
512 std::string filename = mCache->getTextureFileName(mID);
513 S32 filesize = LLAPRFile::size(filename);
514 if (filesize > mOffset)
515 {
516 S32 datasize = TEXTURE_CACHE_ENTRY_SIZE + filesize;
517 mDataSize = llmin(datasize, mDataSize);
518 S32 data_offset = TEXTURE_CACHE_ENTRY_SIZE - mOffset;
519 data_offset = llmax(data_offset, 0);
520 S32 file_size = mDataSize - data_offset;
521 S32 file_offset = mOffset - TEXTURE_CACHE_ENTRY_SIZE;
522 file_offset = llmax(file_offset, 0);
523
524 llassert_always(mDataSize > 0);
525 U8* data = new U8[mDataSize];
526 if (data_offset > 0)
527 {
528 llassert_always(mReadData);
529 llassert_always(data_offset <= mDataSize);
530 memcpy(data, mReadData, data_offset);
531 delete[] mReadData;
532 mReadData = NULL;
533 }
534 llassert_always(mReadData == NULL);
535 mReadData = data;
536
537 mBytesRead = -1;
538 mBytesToRead = file_size;
539 setPriority(LLWorkerThread::PRIORITY_LOW | mPriority);
540 llassert_always(data_offset + mBytesToRead <= mDataSize);
541 mFileHandle = LLLFSThread::sLocal->read(filename,
542 mReadData + data_offset, file_offset, mBytesToRead,
543 new ReadResponder(mCache, mRequestHandle));
544 return false;
545 }
546 else
547 {
548 mDataSize = TEXTURE_CACHE_ENTRY_SIZE;
549 return true; // done
550 }
551 }
552 else
553 {
554 if (mBytesRead >= 0)
555 {
556 if (mBytesRead != mBytesToRead)
557 {
558// llwarns << "LLTextureCacheWorker: " << mID
559// << " incorrect number of bytes read from body: " << mBytesRead
560// << " != " << mBytesToRead << llendl;
561 mDataSize = -1; // failed
562 }
563 return true;
564 }
565 else
566 {
567 return false;
568 }
569 }
570#else
571 std::string filename = mCache->getTextureFileName(mID); 455 std::string filename = mCache->getTextureFileName(mID);
572 S32 filesize = LLAPRFile::size(filename); 456 S32 filesize = LLAPRFile::size(filename);
573 S32 bytes_read = 0; 457
574 if (filesize > mOffset) 458 if (filesize && (filesize + TEXTURE_CACHE_ENTRY_SIZE) > mOffset)
575 { 459 {
576 S32 datasize = TEXTURE_CACHE_ENTRY_SIZE + filesize; 460 S32 max_datasize = TEXTURE_CACHE_ENTRY_SIZE + filesize - mOffset;
577 mDataSize = llmin(datasize, mDataSize); 461 mDataSize = llmin(max_datasize, mDataSize);
578 S32 data_offset = TEXTURE_CACHE_ENTRY_SIZE - mOffset; 462
579 data_offset = llmax(data_offset, 0); 463 S32 data_offset, file_size, file_offset;
580 S32 file_size = mDataSize - data_offset;
581 S32 file_offset = mOffset - TEXTURE_CACHE_ENTRY_SIZE;
582 file_offset = llmax(file_offset, 0);
583 464
465 // Reserve the whole data buffer first
584 U8* data = new U8[mDataSize]; 466 U8* data = new U8[mDataSize];
585 if (data_offset > 0) 467
468 // Set the data file pointers taking the read offset into account. 2 cases:
469 if (mOffset < TEXTURE_CACHE_ENTRY_SIZE)
586 { 470 {
471 // Offset within the header record. That means we read something from the header cache.
472 // Note: most common case is (mOffset = 0), so this is the "normal" code path.
473 data_offset = TEXTURE_CACHE_ENTRY_SIZE - mOffset; // i.e. TEXTURE_CACHE_ENTRY_SIZE if mOffset nul (common case)
474 file_offset = 0;
475 file_size = mDataSize - data_offset;
476 // Copy the raw data we've been holding from the header cache into the new sized buffer
587 llassert_always(mReadData); 477 llassert_always(mReadData);
588 memcpy(data, mReadData, data_offset); 478 memcpy(data, mReadData, data_offset);
589 delete[] mReadData; 479 delete[] mReadData;
480 mReadData = NULL;
481 }
482 else
483 {
484 // Offset bigger than the header record. That means we haven't read anything yet.
485 data_offset = 0;
486 file_offset = mOffset - TEXTURE_CACHE_ENTRY_SIZE;
487 file_size = mDataSize;
488 // No data from header cache to copy in that case, we skipped it all
590 } 489 }
490
491 // Now use that buffer as the object read buffer
492 llassert_always(mReadData == NULL);
591 mReadData = data; 493 mReadData = data;
592 bytes_read = LLAPRFile::readEx(filename, 494
495 // Read the data at last
496 S32 bytes_read = LLAPRFile::readEx(filename,
593 mReadData + data_offset, 497 mReadData + data_offset,
594 file_offset, file_size); 498 file_offset, file_size);
595 if (bytes_read != file_size) 499 if (bytes_read != file_size)
596 { 500 {
597// llwarns << "LLTextureCacheWorker: " << mID 501 llwarns << "LLTextureCacheWorker: " << mID
598// << " incorrect number of bytes read from body: " << bytes_read 502 << " incorrect number of bytes read from body: " << bytes_read
599// << " / " << file_size << llendl; 503 << " / " << file_size << llendl;
504 delete[] mReadData;
505 mReadData = NULL;
600 mDataSize = -1; // failed 506 mDataSize = -1; // failed
601 return true; 507 done = true;
602 } 508 }
603 } 509 }
604 else 510 else
605 { 511 {
606 mDataSize = TEXTURE_CACHE_ENTRY_SIZE; 512 // No body, we're done.
607 } 513 mDataSize = llmax(TEXTURE_CACHE_ENTRY_SIZE - mOffset, 0);
608 514 lldebugs << "No body file for: " << filename << llendl;
609 return true; 515 }
610#endif 516 // Nothing else to do at that point...
517 done = true;
611 } 518 }
612 519
613 return false; 520 // Clean up and exit
521 return done;
614} 522}
615 523
524// This is where *everything* about a texture is written down in the cache system (entry map, header and body)
525// Current assumption are:
526// - the whole data are in a raw form, starting at mWriteData
527// - the size of this raw data is mDataSize and can be smaller than TEXTURE_CACHE_ENTRY_SIZE (the size of a record in the header cache)
528// - the code *does not* support offset writing so there are no difference between buffer addresses and start of data
616bool LLTextureCacheRemoteWorker::doWrite() 529bool LLTextureCacheRemoteWorker::doWrite()
617{ 530{
531 bool done = false;
618 S32 idx = -1; 532 S32 idx = -1;
619 533
620 // No LOCAL state for write() 534 // First state / stage : check that what we're trying to cache is in an OK shape
621
622 if (mState == INIT) 535 if (mState == INIT)
623 { 536 {
537 llassert_always(mOffset == 0); // We currently do not support write offsets
538 llassert_always(mDataSize > 0); // Things will go badly wrong if mDataSize is nul or negative...
539 mState = CACHE;
540 }
541
542 // No LOCAL state for write(): because it doesn't make much sense to cache a local file...
543
544 // Second state / stage : set an entry in the headers entry (texture.entries) file
545 if (!done && (mState == CACHE))
546 {
547 bool alreadyCached = false;
624 S32 cur_imagesize = 0; 548 S32 cur_imagesize = 0;
625 S32 offset = mOffset; 549 // Checks if this image is already in the entry list
626 idx = mCache->getHeaderCacheEntry(mID, false, &cur_imagesize); 550 idx = mCache->getHeaderCacheEntry(mID, cur_imagesize);
627 if (idx >= 0 && cur_imagesize > 0) 551 if (idx >= 0 && (cur_imagesize >= 0))
628 { 552 {
629 offset = TEXTURE_CACHE_ENTRY_SIZE; // don't re-write header 553 alreadyCached = true; // already there and non empty
630 } 554 }
631 idx = mCache->getHeaderCacheEntry(mID, true, &mImageSize); // touch entry 555 idx = mCache->setHeaderCacheEntry(mID, mImageSize); // create or touch the entry
632 if (idx >= 0) 556 if (idx < 0)
633 { 557 {
634 if(cur_imagesize > 0 && mImageSize != cur_imagesize) 558 llwarns << "LLTextureCacheWorker: " << mID
635 { 559 << " Unable to create header entry for writing!" << llendl;
636// llwarns << "Header cache entry size: " << cur_imagesize << " != mImageSize: " << mImageSize << llendl; 560 mDataSize = -1; // failed
637 offset = 0; // re-write header 561 done = true;
638 }
639 mState = offset < TEXTURE_CACHE_ENTRY_SIZE ? HEADER : BODY;
640 } 562 }
641 else 563 else
642 { 564 {
643 mDataSize = -1; // failed 565 if (cur_imagesize > 0 && (mImageSize != cur_imagesize))
644 return true; 566 {
567 alreadyCached = false; // re-write the header if the size changed in all cases
568 }
569 if (alreadyCached && (mDataSize <= TEXTURE_CACHE_ENTRY_SIZE))
570 {
571 // Small texture already cached case: we're done with writing
572 done = true;
573 }
574 else
575 {
576 // If the texture has already been cached, we don't resave the header and go directly to the body part
577 mState = alreadyCached ? BODY : HEADER;
578 }
645 } 579 }
646 } 580 }
647 581
648 if (mState == HEADER) 582 // Third stage / state : write the header record in the header file (texture.cache)
583 if (!done && (mState == HEADER))
649 { 584 {
650#if USE_LFS_WRITE 585 llassert_always(idx >= 0); // we need an entry here or storing the header makes no sense
651 if (mFileHandle == LLLFSThread::nullHandle()) 586 S32 offset = idx * TEXTURE_CACHE_ENTRY_SIZE; // skip to the correct spot in the header file
587 S32 size = TEXTURE_CACHE_ENTRY_SIZE; // record size is fixed for the header
588 S32 bytes_written;
589
590 if (mDataSize < TEXTURE_CACHE_ENTRY_SIZE)
652 { 591 {
653 llassert_always(idx >= 0); 592 // We need to write a full record in the header cache so, if the amount of data is smaller
654 llassert_always(mOffset < TEXTURE_CACHE_ENTRY_SIZE); 593 // than a record, we need to transfer the data to a buffer padded with 0 and write that
655 S32 offset = idx * TEXTURE_CACHE_ENTRY_SIZE + mOffset; 594 U8* padBuffer = new U8[TEXTURE_CACHE_ENTRY_SIZE];
656 S32 size = TEXTURE_CACHE_ENTRY_SIZE - mOffset; 595 memset(padBuffer, 0, TEXTURE_CACHE_ENTRY_SIZE); // Init with zeros
657 mBytesRead = -1; 596 memcpy(padBuffer, mWriteData, mDataSize); // Copy the write buffer
658 mBytesToRead = size; 597 bytes_written = LLAPRFile::writeEx(mCache->mHeaderDataFileName, padBuffer, offset, size);
659 setPriority(LLWorkerThread::PRIORITY_LOW | mPriority); 598 delete [] padBuffer;
660 mFileHandle = LLLFSThread::sLocal->write(mCache->mHeaderDataFileName,
661 mWriteData, offset, mBytesToRead,
662 new WriteResponder(mCache, mRequestHandle));
663 return false;
664 } 599 }
665 else 600 else
666 { 601 {
667 if (mBytesRead >= 0) 602 // Write the header record (== first TEXTURE_CACHE_ENTRY_SIZE bytes of the raw file) in the header file
668 { 603 bytes_written = LLAPRFile::writeEx(mCache->mHeaderDataFileName, mWriteData, offset, size);
669 if (mBytesRead != mBytesToRead)
670 {
671// llwarns << "LLTextureCacheWorker: " << mID
672// << " incorrect number of bytes written to header: " << mBytesRead
673// << " != " << mBytesToRead << llendl;
674 mDataSize = -1; // failed
675 return true;
676 }
677 if (mDataSize <= mBytesToRead)
678 {
679 return true; // done
680 }
681 else
682 {
683 mFileHandle = LLLFSThread::nullHandle();
684 mState = BODY;
685 }
686 }
687 else
688 {
689 return false;
690 }
691 } 604 }
692#else
693 llassert_always(idx >= 0);
694 llassert_always(mOffset < TEXTURE_CACHE_ENTRY_SIZE);
695 S32 offset = idx * TEXTURE_CACHE_ENTRY_SIZE + mOffset;
696 S32 size = TEXTURE_CACHE_ENTRY_SIZE - mOffset;
697 S32 bytes_written = LLAPRFile::writeEx(mCache->mHeaderDataFileName, mWriteData, offset, size);
698 605
699 if (bytes_written <= 0) 606 if (bytes_written <= 0)
700 { 607 {
701// llwarns << "LLTextureCacheWorker: missing entry: " << mID << llendl; 608 llwarns << "LLTextureCacheWorker: " << mID
609 << " Unable to write header entry!" << llendl;
702 mDataSize = -1; // failed 610 mDataSize = -1; // failed
703 return true; 611 done = true;
704 } 612 }
705 613
706 if (mDataSize <= size) 614 // If we wrote everything (may be more with padding) in the header cache,
615 // we're done so we don't have a body to store
616 if (mDataSize <= bytes_written)
707 { 617 {
708 return true; // done 618 done = true;
709 } 619 }
710 else 620 else
711 { 621 {
712 mState = BODY; 622 mState = BODY;
713 } 623 }
714#endif
715 } 624 }
716 625
717 if (mState == BODY) 626 // Fourth stage / state : write the body file, i.e. the rest of the texture in a "UUID" file name
627 if (!done && (mState == BODY))
718 { 628 {
719#if USE_LFS_WRITE 629 llassert(mDataSize > TEXTURE_CACHE_ENTRY_SIZE); // wouldn't make sense to be here otherwise...
720 if (mFileHandle == LLLFSThread::nullHandle()) 630 S32 file_size = mDataSize - TEXTURE_CACHE_ENTRY_SIZE;
631 if ((file_size > 0) && mCache->updateTextureEntryList(mID, file_size))
721 { 632 {
722 S32 data_offset = TEXTURE_CACHE_ENTRY_SIZE - mOffset; 633 // build the cache file name from the UUID
723 data_offset = llmax(data_offset, 0); 634 std::string filename = mCache->getTextureFileName(mID);
724 S32 file_size = mDataSize - data_offset; 635// llinfos << "Writing Body: " << filename << " Bytes: " << file_offset+file_size << llendl;
725 S32 file_offset = mOffset - TEXTURE_CACHE_ENTRY_SIZE; 636 S32 bytes_written = LLAPRFile::writeEx( filename,
726 file_offset = llmax(file_offset, 0); 637 mWriteData + TEXTURE_CACHE_ENTRY_SIZE,
727 if (file_size > 0 && mCache->appendToTextureEntryList(mID, file_size)) 638 0, file_size);
728 {
729 std::string filename = mCache->getTextureFileName(mID);
730 mBytesRead = -1;
731 mBytesToRead = file_size;
732 setPriority(LLWorkerThread::PRIORITY_LOW | mPriority);
733 mFileHandle = LLLFSThread::sLocal->write(filename,
734 mWriteData + data_offset, file_offset, mBytesToRead,
735 new WriteResponder(mCache, mRequestHandle));
736 return false;
737 }
738 else
739 {
740 mDataSize = 0; // no data written
741 return true; // done
742 }
743 }
744 else
745 {
746 if (mBytesRead >= 0)
747 {
748 if (mBytesRead != mBytesToRead)
749 {
750// llwarns << "LLTextureCacheWorker: " << mID
751// << " incorrect number of bytes written to body: " << mBytesRead
752// << " != " << mBytesToRead << llendl;
753 mDataSize = -1; // failed
754 }
755 return true;
756 }
757 else
758 {
759 return false;
760 }
761 }
762#else
763 S32 data_offset = TEXTURE_CACHE_ENTRY_SIZE - mOffset;
764 data_offset = llmax(data_offset, 0);
765 S32 file_size = mDataSize - data_offset;
766 S32 file_offset = mOffset - TEXTURE_CACHE_ENTRY_SIZE;
767 file_offset = llmax(file_offset, 0);
768 S32 bytes_written = 0;
769 if (file_size > 0 && mCache->appendToTextureEntryList(mID, file_size))
770 {
771 std::string filename = mCache->getTextureFileName(mID);
772
773 bytes_written = LLAPRFile::writeEx(filename,
774 mWriteData + data_offset,
775 file_offset, file_size);
776 if (bytes_written <= 0) 639 if (bytes_written <= 0)
777 { 640 {
641 llwarns << "LLTextureCacheWorker: " << mID
642 << " incorrect number of bytes written to body: " << bytes_written
643 << " / " << file_size << llendl;
778 mDataSize = -1; // failed 644 mDataSize = -1; // failed
645 done = true;
779 } 646 }
780 } 647 }
781 else 648 else
782 { 649 {
783 mDataSize = 0; // no data written 650 mDataSize = 0; // no data written
784 } 651 }
785 652 // Nothing else to do at that point...
786 return true; 653 done = true;
787#endif
788 } 654 }
789 655
790 return false; 656 // Clean up and exit
657 return done;
791} 658}
792 659
793//virtual 660//virtual
794bool LLTextureCacheWorker::doWork(S32 param) 661bool LLTextureCacheWorker::doWork(S32 param)
795{ 662{
796// *TODO reenable disabled apr_pool usage disabled due to maint-render-9 merge breakage -brad
797 //allocate a new local apr_pool
798// LLAPRPool pool ;
799
800 //save the current mFileAPRPool to avoid breaking anything.
801// apr_pool_t* old_pool = mCache->getFileAPRPool() ;
802 //make mFileAPRPool to point to the local one
803// mCache->setFileAPRPool(pool.getAPRPool()) ;
804
805 bool res = false; 663 bool res = false;
806 if (param == 0) // read 664 if (param == 0) // read
807 { 665 {
@@ -815,10 +673,6 @@ bool LLTextureCacheWorker::doWork(S32 param)
815 { 673 {
816 llassert_always(0); 674 llassert_always(0);
817 } 675 }
818
819 //set mFileAPRPool back, the local one will be released automatically.
820// mCache->setFileAPRPool(old_pool) ;
821
822 return res; 676 return res;
823} 677}
824 678
@@ -884,6 +738,7 @@ LLTextureCache::LLTextureCache(bool threaded)
884 mWorkersMutex(NULL), 738 mWorkersMutex(NULL),
885 mHeaderMutex(NULL), 739 mHeaderMutex(NULL),
886 mListMutex(NULL), 740 mListMutex(NULL),
741 mHeaderAPRFile(NULL),
887 mReadOnly(FALSE), 742 mReadOnly(FALSE),
888 mTexturesSizeTotal(0), 743 mTexturesSizeTotal(0),
889 mDoPurge(FALSE) 744 mDoPurge(FALSE)
@@ -892,9 +747,6 @@ LLTextureCache::LLTextureCache(bool threaded)
892 747
893LLTextureCache::~LLTextureCache() 748LLTextureCache::~LLTextureCache()
894{ 749{
895 purgeTextureFilesTimeSliced(TRUE); // force-flush all pending file deletes
896
897 // apr_pool_destroy(mFileAPRPool);
898} 750}
899 751
900////////////////////////////////////////////////////////////////////////////// 752//////////////////////////////////////////////////////////////////////////////
@@ -926,6 +778,9 @@ S32 LLTextureCache::update(U32 max_time_ms)
926 } 778 }
927 } 779 }
928 780
781 unlockWorkers();
782
783 // call 'completed' with workers list unlocked (may call readComplete() or writeComplete()
929 for (responder_list_t::iterator iter1 = completed_list.begin(); 784 for (responder_list_t::iterator iter1 = completed_list.begin();
930 iter1 != completed_list.end(); ++iter1) 785 iter1 != completed_list.end(); ++iter1)
931 { 786 {
@@ -934,8 +789,6 @@ S32 LLTextureCache::update(U32 max_time_ms)
934 responder->completed(success); 789 responder->completed(success);
935 } 790 }
936 791
937 unlockWorkers();
938
939 return res; 792 return res;
940} 793}
941 794
@@ -954,32 +807,48 @@ std::string LLTextureCache::getTextureFileName(const LLUUID& id)
954{ 807{
955 std::string idstr = id.asString(); 808 std::string idstr = id.asString();
956 std::string delem = gDirUtilp->getDirDelimiter(); 809 std::string delem = gDirUtilp->getDirDelimiter();
957 std::string filename = mTexturesDirName + delem + idstr[0] + delem + idstr; 810 std::string filename = mTexturesDirName + delem + idstr[0] + delem + idstr + ".texture";
958 return filename; 811 return filename;
959} 812}
960 813
961bool LLTextureCache::appendToTextureEntryList(const LLUUID& id, S32 bodysize) 814bool LLTextureCache::updateTextureEntryList(const LLUUID& id, S32 bodysize)
962{ 815{
963 bool res = false; 816 bool res = false;
964 bool purge = false; 817 bool purge = false;
965 // Append UUID to end of texture entries
966 { 818 {
967 LLMutexLock lock(&mHeaderMutex); 819 LLMutexLock lock(&mHeaderMutex);
968 size_map_t::iterator iter = mTexturesSizeMap.find(id); 820 size_map_t::iterator iter1 = mTexturesSizeMap.find(id);
969 if (iter == mTexturesSizeMap.end() || iter->second < bodysize) 821 if (iter1 == mTexturesSizeMap.end() || iter1->second < bodysize)
970 { 822 {
971 llassert_always(bodysize > 0); 823 llassert_always(bodysize > 0);
972 Entry* entry = new Entry(id, bodysize, time(NULL));
973 824
974 LLAPRFile::writeEx(mTexturesDirEntriesFileName, 825 S32 oldbodysize = 0;
975 (U8*)entry, -1, 1*sizeof(Entry)); 826 if (iter1 != mTexturesSizeMap.end())
976 delete entry;
977 if (iter != mTexturesSizeMap.end())
978 { 827 {
979 mTexturesSizeTotal -= iter->second; 828 oldbodysize = iter1->second;
980 } 829 }
830
831 Entry entry;
832 S32 idx = openAndReadEntry(id, entry, false);
833 if (idx < 0)
834 {
835 // TODO: change to llwarns
836 llerrs << "Failed to open entry: " << id << llendl;
837 removeFromCache(id);
838 return false;
839 }
840 else if (oldbodysize != entry.mBodySize)
841 {
842 // TODO: change to llwarns
843 llerrs << "Entry mismatch in mTextureSizeMap / mHeaderIDMap"
844 << " idx=" << idx << " oldsize=" << oldbodysize << " entrysize=" << entry.mBodySize << llendl;
845 }
846 entry.mBodySize = bodysize;
847 writeEntryAndClose(idx, entry);
848
849 mTexturesSizeTotal -= oldbodysize;
981 mTexturesSizeTotal += bodysize; 850 mTexturesSizeTotal += bodysize;
982 mTexturesSizeMap[id] = bodysize; 851
983 if (mTexturesSizeTotal > sCacheMaxTexturesSize) 852 if (mTexturesSizeTotal > sCacheMaxTexturesSize)
984 { 853 {
985 purge = true; 854 purge = true;
@@ -998,7 +867,7 @@ bool LLTextureCache::appendToTextureEntryList(const LLUUID& id, S32 bodysize)
998 867
999//static 868//static
1000const S32 MAX_REASONABLE_FILE_SIZE = 512*1024*1024; // 512 MB 869const S32 MAX_REASONABLE_FILE_SIZE = 512*1024*1024; // 512 MB
1001F32 LLTextureCache::sHeaderCacheVersion = 1.0f; 870F32 LLTextureCache::sHeaderCacheVersion = 1.2f;
1002U32 LLTextureCache::sCacheMaxEntries = MAX_REASONABLE_FILE_SIZE / TEXTURE_CACHE_ENTRY_SIZE; 871U32 LLTextureCache::sCacheMaxEntries = MAX_REASONABLE_FILE_SIZE / TEXTURE_CACHE_ENTRY_SIZE;
1003S64 LLTextureCache::sCacheMaxTexturesSize = 0; // no limit 872S64 LLTextureCache::sCacheMaxTexturesSize = 0; // no limit
1004const char* entries_filename = "texture.entries"; 873const char* entries_filename = "texture.entries";
@@ -1011,7 +880,6 @@ void LLTextureCache::setDirNames(ELLPath location)
1011 mHeaderEntriesFileName = gDirUtilp->getExpandedFilename(location, entries_filename); 880 mHeaderEntriesFileName = gDirUtilp->getExpandedFilename(location, entries_filename);
1012 mHeaderDataFileName = gDirUtilp->getExpandedFilename(location, cache_filename); 881 mHeaderDataFileName = gDirUtilp->getExpandedFilename(location, cache_filename);
1013 mTexturesDirName = gDirUtilp->getExpandedFilename(location, textures_dirname); 882 mTexturesDirName = gDirUtilp->getExpandedFilename(location, textures_dirname);
1014 mTexturesDirEntriesFileName = mTexturesDirName + delem + entries_filename;
1015} 883}
1016 884
1017void LLTextureCache::purgeCache(ELLPath location) 885void LLTextureCache::purgeCache(ELLPath location)
@@ -1019,7 +887,7 @@ void LLTextureCache::purgeCache(ELLPath location)
1019 if (!mReadOnly) 887 if (!mReadOnly)
1020 { 888 {
1021 setDirNames(location); 889 setDirNames(location);
1022 890 llassert_always(mHeaderAPRFile == NULL);
1023 LLAPRFile::remove(mHeaderEntriesFileName); 891 LLAPRFile::remove(mHeaderEntriesFileName);
1024 LLAPRFile::remove(mHeaderDataFileName); 892 LLAPRFile::remove(mHeaderDataFileName);
1025 } 893 }
@@ -1062,80 +930,315 @@ S64 LLTextureCache::initCache(ELLPath location, S64 max_size, BOOL read_only)
1062 return max_size; // unused cache space 930 return max_size; // unused cache space
1063} 931}
1064 932
1065struct lru_data 933//----------------------------------------------------------------------------
934// mHeaderMutex must be locked for the following functions!
935
936LLAPRFile* LLTextureCache::openHeaderEntriesFile(bool readonly, S32 offset)
937{
938 llassert_always(mHeaderAPRFile == NULL);
939 apr_int32_t flags = readonly ? APR_READ|APR_BINARY : APR_READ|APR_WRITE|APR_BINARY;
940 mHeaderAPRFile = new LLAPRFile(mHeaderEntriesFileName, flags, LLAPRFile::local);
941 mHeaderAPRFile->seek(APR_SET, offset);
942 return mHeaderAPRFile;
943}
944
945void LLTextureCache::closeHeaderEntriesFile()
946{
947 llassert_always(mHeaderAPRFile != NULL);
948 delete mHeaderAPRFile;
949 mHeaderAPRFile = NULL;
950}
951
952void LLTextureCache::readEntriesHeader()
953{
954 // mHeaderEntriesInfo initializes to default values so safe not to read it
955 llassert_always(mHeaderAPRFile == NULL);
956 if (LLAPRFile::isExist(mHeaderEntriesFileName))
957 {
958 LLAPRFile::readEx(mHeaderEntriesFileName, (U8*)&mHeaderEntriesInfo, 0, sizeof(EntriesInfo));
959 }
960}
961
962void LLTextureCache::writeEntriesHeader()
1066{ 963{
1067 lru_data(U32 t, S32 i, const LLUUID& id) { time=t; index=i; uuid=id; } 964 llassert_always(mHeaderAPRFile == NULL);
1068 U32 time; 965 if (!mReadOnly)
1069 S32 index; 966 {
1070 LLUUID uuid; 967 LLAPRFile::writeEx(mHeaderEntriesFileName, (U8*)&mHeaderEntriesInfo, 0, sizeof(EntriesInfo));
1071 struct Compare 968 }
1072 { 969}
1073 // lhs < rhs 970
1074 typedef const lru_data* lru_data_ptr; 971static S32 mHeaderEntriesMaxWriteIdx = 0;
1075 bool operator()(const lru_data_ptr& a, const lru_data_ptr& b) const 972
973S32 LLTextureCache::openAndReadEntry(const LLUUID& id, Entry& entry, bool create)
974{
975 S32 idx = -1;
976
977 id_map_t::iterator iter1 = mHeaderIDMap.find(id);
978 if (iter1 != mHeaderIDMap.end())
979 {
980 idx = iter1->second;
981 }
982
983 if (idx < 0)
984 {
985 if (create && !mReadOnly)
1076 { 986 {
1077 if(a->time == b->time) 987 if (mHeaderEntriesInfo.mEntries < sCacheMaxEntries)
1078 return (a->index < b->index); 988 {
989 // Add an entry to the end of the list
990 idx = mHeaderEntriesInfo.mEntries++;
991
992 }
993 else if (!mFreeList.empty())
994 {
995 idx = *(mFreeList.begin());
996 mFreeList.erase(mFreeList.begin());
997 }
1079 else 998 else
1080 return (a->time >= b->time); 999 {
1000 // Look for a still valid entry in the LRU
1001 for (std::set<LLUUID>::iterator iter2 = mLRU.begin(); iter2 != mLRU.end();)
1002 {
1003 std::set<LLUUID>::iterator curiter2 = iter2++;
1004 LLUUID oldid = *curiter2;
1005 // Erase entry from LRU regardless
1006 mLRU.erase(curiter2);
1007 // Look up entry and use it if it is valid
1008 id_map_t::iterator iter3 = mHeaderIDMap.find(oldid);
1009 if (iter3 != mHeaderIDMap.end() && iter3->second >= 0)
1010 {
1011 idx = iter3->second;
1012 mHeaderIDMap.erase(oldid);
1013 mTexturesSizeMap.erase(oldid);
1014 break;
1015 }
1016 }
1017 // if (idx < 0) at this point, we will rebuild the LRU
1018 // and retry if called from setHeaderCacheEntry(),
1019 // otherwise this shouldn't happen and will trigger an error
1020 }
1021 if (idx >= 0)
1022 {
1023 // Set the header index
1024 mHeaderIDMap[id] = idx;
1025 llassert_always(mTexturesSizeMap.erase(id) == 0);
1026 // Initialize the entry (will get written later)
1027 entry.init(id, time(NULL));
1028 // Update Header
1029 writeEntriesHeader();
1030 // Write Entry
1031 S32 offset = sizeof(EntriesInfo) + idx * sizeof(Entry);
1032 LLAPRFile* aprfile = openHeaderEntriesFile(false, offset);
1033 S32 bytes_written = aprfile->write((void*)&entry, (S32)sizeof(Entry));
1034 llassert_always(bytes_written == sizeof(Entry));
1035 mHeaderEntriesMaxWriteIdx = llmax(mHeaderEntriesMaxWriteIdx, idx);
1036 closeHeaderEntriesFile();
1037 }
1081 } 1038 }
1082 }; 1039 }
1083}; 1040 else
1041 {
1042 // Remove this entry from the LRU if it exists
1043 mLRU.erase(id);
1044 // Read the entry
1045 S32 offset = sizeof(EntriesInfo) + idx * sizeof(Entry);
1046 LLAPRFile* aprfile = openHeaderEntriesFile(true, offset);
1047 S32 bytes_read = aprfile->read((void*)&entry, (S32)sizeof(Entry));
1048 llassert_always(bytes_read == sizeof(Entry));
1049 llassert_always(entry.mImageSize == 0 || entry.mImageSize == -1 || entry.mImageSize > entry.mBodySize);
1050 closeHeaderEntriesFile();
1051 }
1052 return idx;
1053}
1054
1055void LLTextureCache::writeEntryAndClose(S32 idx, Entry& entry)
1056{
1057 if (idx >= 0)
1058 {
1059 if (!mReadOnly)
1060 {
1061 entry.mTime = time(NULL);
1062 llassert_always(entry.mImageSize == 0 || entry.mImageSize == -1 || entry.mImageSize > entry.mBodySize);
1063 if (entry.mBodySize > 0)
1064 {
1065 mTexturesSizeMap[entry.mID] = entry.mBodySize;
1066 }
1067// llinfos << "Updating TE: " << idx << ": " << id << " Size: " << entry.mBodySize << " Time: " << entry.mTime << llendl;
1068 S32 offset = sizeof(EntriesInfo) + idx * sizeof(Entry);
1069 LLAPRFile* aprfile = openHeaderEntriesFile(false, offset);
1070 S32 bytes_written = aprfile->write((void*)&entry, (S32)sizeof(Entry));
1071 llassert_always(bytes_written == sizeof(Entry));
1072 mHeaderEntriesMaxWriteIdx = llmax(mHeaderEntriesMaxWriteIdx, idx);
1073 closeHeaderEntriesFile();
1074 }
1075 }
1076}
1077
1078U32 LLTextureCache::openAndReadEntries(std::vector<Entry>& entries)
1079{
1080 U32 num_entries = mHeaderEntriesInfo.mEntries;
1081
1082 mHeaderIDMap.clear();
1083 mTexturesSizeMap.clear();
1084 mFreeList.clear();
1085 mTexturesSizeTotal = 0;
1086
1087 LLAPRFile* aprfile = openHeaderEntriesFile(false, (S32)sizeof(EntriesInfo));
1088 for (U32 idx=0; idx<num_entries; idx++)
1089 {
1090 Entry entry;
1091 S32 bytes_read = aprfile->read((void*)(&entry), (S32)sizeof(Entry));
1092 if (bytes_read < sizeof(Entry))
1093 {
1094 llwarns << "Corrupted header entries, failed at " << idx << " / " << num_entries << llendl;
1095 closeHeaderEntriesFile();
1096 purgeAllTextures(false);
1097 return 0;
1098 }
1099 entries.push_back(entry);
1100// llinfos << "ENTRY: " << entry.mTime << " TEX: " << entry.mID << " IDX: " << idx << " Size: " << entry.mImageSize << llendl;
1101 if (entry.mImageSize < 0)
1102 {
1103 mFreeList.insert(idx);
1104 }
1105 else
1106 {
1107 mHeaderIDMap[entry.mID] = idx;
1108 if (entry.mBodySize > 0)
1109 {
1110 mTexturesSizeMap[entry.mID] = entry.mBodySize;
1111 mTexturesSizeTotal += entry.mBodySize;
1112 }
1113 llassert_always(entry.mImageSize == 0 || entry.mImageSize > entry.mBodySize);
1114 }
1115 }
1116 closeHeaderEntriesFile();
1117 return num_entries;
1118}
1119
1120void LLTextureCache::writeEntriesAndClose(const std::vector<Entry>& entries)
1121{
1122 S32 num_entries = entries.size();
1123 llassert_always(num_entries == mHeaderEntriesInfo.mEntries);
1124
1125 if (!mReadOnly)
1126 {
1127 LLAPRFile* aprfile = openHeaderEntriesFile(false, (S32)sizeof(EntriesInfo));
1128 for (S32 idx=0; idx<num_entries; idx++)
1129 {
1130 S32 bytes_written = aprfile->write((void*)(&entries[idx]), (S32)sizeof(Entry));
1131 llassert_always(bytes_written == sizeof(Entry));
1132 }
1133 mHeaderEntriesMaxWriteIdx = llmax(mHeaderEntriesMaxWriteIdx, num_entries-1);
1134 closeHeaderEntriesFile();
1135 }
1136}
1137
1138//----------------------------------------------------------------------------
1084 1139
1085// Called from either the main thread or the worker thread 1140// Called from either the main thread or the worker thread
1086void LLTextureCache::readHeaderCache() 1141void LLTextureCache::readHeaderCache()
1087{ 1142{
1088 LLMutexLock lock(&mHeaderMutex); 1143 LLMutexLock lock(&mHeaderMutex);
1089 mHeaderEntriesInfo.mVersion = 0.f; 1144
1090 mHeaderEntriesInfo.mEntries = 0; 1145 mLRU.clear(); // always clear the LRU
1091 if (LLAPRFile::isExist(mHeaderEntriesFileName)) 1146
1092 { 1147 readEntriesHeader();
1093 LLAPRFile::readEx(mHeaderEntriesFileName, 1148
1094 (U8*)&mHeaderEntriesInfo, 0, sizeof(EntriesInfo));
1095 }
1096 if (mHeaderEntriesInfo.mVersion != sHeaderCacheVersion) 1149 if (mHeaderEntriesInfo.mVersion != sHeaderCacheVersion)
1097 { 1150 {
1098 if (!mReadOnly) 1151 if (!mReadOnly)
1099 { 1152 {
1100 // Info with 0 entries 1153 purgeAllTextures(false);
1101 mHeaderEntriesInfo.mVersion = sHeaderCacheVersion;
1102
1103 LLAPRFile::writeEx(mHeaderEntriesFileName,
1104 (U8*)&mHeaderEntriesInfo, 0, sizeof(EntriesInfo));
1105 } 1154 }
1106 } 1155 }
1107 else 1156 else
1108 { 1157 {
1109 S32 num_entries = mHeaderEntriesInfo.mEntries; 1158 std::vector<Entry> entries;
1159 U32 num_entries = openAndReadEntries(entries);
1110 if (num_entries) 1160 if (num_entries)
1111 { 1161 {
1112 Entry* entries = new Entry[num_entries]; 1162 U32 empty_entries = 0;
1163 typedef std::pair<U32, LLUUID> lru_data_t;
1164 std::set<lru_data_t> lru;
1165 std::vector<LLUUID> purge_list;
1166 for (U32 i=0; i<num_entries; i++)
1113 { 1167 {
1114 LLAPRFile::readEx(mHeaderEntriesFileName, 1168 Entry& entry = entries[i];
1115 (U8*)entries, sizeof(EntriesInfo), num_entries*sizeof(Entry)); 1169 const LLUUID& id = entry.mID;
1170 if (entry.mImageSize < 0)
1171 {
1172 // This will be in the Free List, don't put it in the LRY
1173 ++empty_entries;
1174 }
1175 else
1176 {
1177 lru.insert(std::make_pair(entry.mTime, id));
1178 if (entry.mBodySize > 0)
1179 {
1180 if (entry.mBodySize > entry.mImageSize)
1181 {
1182 // Shouldn't happen, failsafe only
1183 llwarns << "Bad entry: " << i << ": " << id << ": BodySize: " << entry.mBodySize << llendl;
1184 purge_list.push_back(id);
1185 }
1186 }
1187 }
1116 } 1188 }
1117 typedef std::set<lru_data*, lru_data::Compare> lru_set_t; 1189 if (num_entries > sCacheMaxEntries)
1118 lru_set_t lru;
1119 for (S32 i=0; i<num_entries; i++)
1120 { 1190 {
1121 if (entries[i].mSize >= 0) // -1 indicates erased entry, skip 1191 // Special case: cache size was reduced, need to remove entries
1192 // Note: After we prune entries, we will call this again and create the LRU
1193 U32 entries_to_purge = (num_entries-empty_entries) - sCacheMaxEntries;
1194 if (entries_to_purge > 0)
1122 { 1195 {
1123 const LLUUID& id = entries[i].mID; 1196 for (std::set<lru_data_t>::iterator iter = lru.begin(); iter != lru.end(); ++iter)
1124 lru.insert(new lru_data(entries[i].mTime, i, id)); 1197 {
1125 mHeaderIDMap[id] = i; 1198 purge_list.push_back(iter->second);
1199 if (--entries_to_purge <= 0)
1200 break;
1201 }
1126 } 1202 }
1127 } 1203 }
1128 mLRU.clear(); 1204 else
1129 S32 lru_entries = sCacheMaxEntries / 10;
1130 for (lru_set_t::iterator iter = lru.begin(); iter != lru.end(); ++iter)
1131 { 1205 {
1132 lru_data* data = *iter; 1206 S32 lru_entries = (S32)((F32)sCacheMaxEntries * TEXTURE_CACHE_LRU_SIZE);
1133 mLRU[data->index] = data->uuid; 1207 for (std::set<lru_data_t>::iterator iter = lru.begin(); iter != lru.end(); ++iter)
1134 if (--lru_entries <= 0) 1208 {
1135 break; 1209 mLRU.insert(iter->second);
1210// llinfos << "LRU: " << iter->first << " : " << iter->second << llendl;
1211 if (--lru_entries <= 0)
1212 break;
1213 }
1214 }
1215
1216 if (purge_list.size() > 0)
1217 {
1218 for (std::vector<LLUUID>::iterator iter = purge_list.begin(); iter != purge_list.end(); ++iter)
1219 {
1220 removeFromCache(*iter);
1221 }
1222 // If we removed any entries, we need to rebuild the entries list,
1223 // write the header, and call this again
1224 std::vector<Entry> new_entries;
1225 for (U32 i=0; i<num_entries; i++)
1226 {
1227 const Entry& entry = entries[i];
1228 if (entry.mImageSize >=0)
1229 {
1230 new_entries.push_back(entry);
1231 }
1232 }
1233 llassert_always(new_entries.size() <= sCacheMaxEntries);
1234 mHeaderEntriesInfo.mEntries = new_entries.size();
1235 writeEntriesAndClose(new_entries);
1236 readHeaderCache(); // repeat with new entries file
1237 }
1238 else
1239 {
1240 writeEntriesAndClose(entries);
1136 } 1241 }
1137 for_each(lru.begin(), lru.end(), DeletePointer());
1138 delete[] entries;
1139 } 1242 }
1140 } 1243 }
1141} 1244}
@@ -1158,13 +1261,21 @@ void LLTextureCache::purgeAllTextures(bool purge_directories)
1158 LLFile::rmdir(dirname); 1261 LLFile::rmdir(dirname);
1159 } 1262 }
1160 } 1263 }
1161 LLAPRFile::remove(mTexturesDirEntriesFileName);
1162 if (purge_directories) 1264 if (purge_directories)
1163 { 1265 {
1164 LLFile::rmdir(mTexturesDirName); 1266 LLFile::rmdir(mTexturesDirName);
1165 } 1267 }
1166 } 1268 }
1269 mHeaderIDMap.clear();
1167 mTexturesSizeMap.clear(); 1270 mTexturesSizeMap.clear();
1271 mTexturesSizeTotal = 0;
1272 mFreeList.clear();
1273 mTexturesSizeTotal = 0;
1274
1275 // Info with 0 entries
1276 mHeaderEntriesInfo.mVersion = sHeaderCacheVersion;
1277 mHeaderEntriesInfo.mEntries = 0;
1278 writeEntriesHeader();
1168} 1279}
1169 1280
1170void LLTextureCache::purgeTextures(bool validate) 1281void LLTextureCache::purgeTextures(bool validate)
@@ -1178,50 +1289,37 @@ void LLTextureCache::purgeTextures(bool validate)
1178 LLAppViewer::instance()->pauseMainloopTimeout(); 1289 LLAppViewer::instance()->pauseMainloopTimeout();
1179 1290
1180 LLMutexLock lock(&mHeaderMutex); 1291 LLMutexLock lock(&mHeaderMutex);
1181 1292
1182 S32 filesize = LLAPRFile::size(mTexturesDirEntriesFileName); 1293 llinfos << "TEXTURE CACHE: Purging." << llendl;
1183 S32 num_entries = filesize / sizeof(Entry); 1294
1184 if (num_entries * (S32)sizeof(Entry) != filesize) 1295 // Read the entries list
1185 { 1296 std::vector<Entry> entries;
1186 LL_WARNS("TextureCache") << "Bad cache file: " << mTexturesDirEntriesFileName << " Purging." << LL_ENDL; 1297 U32 num_entries = openAndReadEntries(entries);
1187 purgeAllTextures(false); 1298 if (!num_entries)
1188 return;
1189 }
1190 if (num_entries == 0)
1191 { 1299 {
1192 return; // nothing to do 1300 writeEntriesAndClose(entries);
1301 return; // nothing to purge
1193 } 1302 }
1194 1303
1195 Entry* entries = new Entry[num_entries]; 1304 // Use mTexturesSizeMap to collect UUIDs of textures with bodies
1196 S32 bytes_read = LLAPRFile::readEx(mTexturesDirEntriesFileName, 1305 typedef std::set<std::pair<U32,S32> > time_idx_set_t;
1197 (U8*)entries, 0, num_entries*sizeof(Entry)); 1306 std::set<std::pair<U32,S32> > time_idx_set;
1198 if (bytes_read != filesize) 1307 for (size_map_t::iterator iter1 = mTexturesSizeMap.begin();
1308 iter1 != mTexturesSizeMap.end(); ++iter1)
1199 { 1309 {
1200 LL_WARNS("TextureCache") << "Bad cache file (2): " << mTexturesDirEntriesFileName << " Purging." << LL_ENDL; 1310 if (iter1->second > 0)
1201 purgeAllTextures(false);
1202 return;
1203 }
1204
1205 LL_DEBUGS("TextureCache") << "TEXTURE CACHE: Reading " << num_entries << " Entries from " << mTexturesDirEntriesFileName << LL_ENDL;
1206
1207 std::map<LLUUID, S32> entry_idx_map;
1208 S64 total_size = 0;
1209 for (S32 idx=0; idx<num_entries; idx++)
1210 {
1211 const LLUUID& id = entries[idx].mID;
1212 LL_DEBUGS("TextureCache") << "Entry: " << id << " Size: " << entries[idx].mSize << " Time: " << entries[idx].mTime << LL_ENDL;
1213 std::map<LLUUID, S32>::iterator iter = entry_idx_map.find(id);
1214 if (iter != entry_idx_map.end())
1215 { 1311 {
1216 // Newer entry replacing older entry 1312 id_map_t::iterator iter2 = mHeaderIDMap.find(iter1->first);
1217 S32 pidx = iter->second; 1313 if (iter2 != mHeaderIDMap.end())
1218 total_size -= entries[pidx].mSize; 1314 {
1219 entries[pidx].mSize = 0; // flag: skip older entry 1315 S32 idx = iter2->second;
1316 time_idx_set.insert(std::make_pair(entries[idx].mTime, idx));
1317// llinfos << "TIME: " << entries[idx].mTime << " TEX: " << entries[idx].mID << " IDX: " << idx << " Size: " << entries[idx].mImageSize << llendl;
1318 }
1220 } 1319 }
1221 entry_idx_map[id] = idx;
1222 total_size += entries[idx].mSize;
1223 } 1320 }
1224 1321
1322 // Validate 1/256th of the files on startup
1225 U32 validate_idx = 0; 1323 U32 validate_idx = 0;
1226 if (validate) 1324 if (validate)
1227 { 1325 {
@@ -1230,19 +1328,17 @@ void LLTextureCache::purgeTextures(bool validate)
1230 gSavedSettings.setU32("CacheValidateCounter", next_idx); 1328 gSavedSettings.setU32("CacheValidateCounter", next_idx);
1231 LL_DEBUGS("TextureCache") << "TEXTURE CACHE: Validating: " << validate_idx << LL_ENDL; 1329 LL_DEBUGS("TextureCache") << "TEXTURE CACHE: Validating: " << validate_idx << LL_ENDL;
1232 } 1330 }
1233 1331
1234 S64 min_cache_size = sCacheMaxTexturesSize / 100 * 95; 1332 S64 cache_size = mTexturesSizeTotal;
1333 S64 purged_cache_size = (sCacheMaxTexturesSize * (S64)((1.f-TEXTURE_CACHE_PURGE_AMOUNT)*100)) / 100;
1235 S32 purge_count = 0; 1334 S32 purge_count = 0;
1236 S32 next_idx = 0; 1335 for (time_idx_set_t::iterator iter = time_idx_set.begin();
1237 for (S32 idx=0; idx<num_entries; idx++) 1336 iter != time_idx_set.end(); ++iter)
1238 { 1337 {
1239 if (entries[idx].mSize == 0) 1338 S32 idx = iter->second;
1240 {
1241 continue;
1242 }
1243 bool purge_entry = false; 1339 bool purge_entry = false;
1244 std::string filename = getTextureFileName(entries[idx].mID); 1340 std::string filename = getTextureFileName(entries[idx].mID);
1245 if (total_size >= min_cache_size) 1341 if (cache_size >= purged_cache_size)
1246 { 1342 {
1247 purge_entry = true; 1343 purge_entry = true;
1248 } 1344 }
@@ -1252,112 +1348,47 @@ void LLTextureCache::purgeTextures(bool validate)
1252 S32 uuididx = entries[idx].mID.mData[0]; 1348 S32 uuididx = entries[idx].mID.mData[0];
1253 if (uuididx == validate_idx) 1349 if (uuididx == validate_idx)
1254 { 1350 {
1255 LL_DEBUGS("TextureCache") << "Validating: " << filename << "Size: " << entries[idx].mSize << LL_ENDL; 1351 LL_DEBUGS("TextureCache") << "Validating: " << filename << "Size: " << entries[idx].mBodySize << LL_ENDL;
1256 S32 bodysize = LLAPRFile::size(filename); 1352 S32 bodysize = LLAPRFile::size(filename);
1257 if (bodysize != entries[idx].mSize) 1353 if (bodysize != entries[idx].mBodySize)
1258 { 1354 {
1259 LL_WARNS("TextureCache") << "TEXTURE CACHE BODY HAS BAD SIZE: " << bodysize << " != " << entries[idx].mSize 1355 LL_WARNS("TextureCache") << "TEXTURE CACHE BODY HAS BAD SIZE: " << bodysize << " != " << entries[idx].mBodySize
1260 << filename << LL_ENDL; 1356 << filename << LL_ENDL;
1261 purge_entry = true; 1357 purge_entry = true;
1262 } 1358 }
1263 } 1359 }
1264 } 1360 }
1265 if (purge_entry) 1361 else
1266 { 1362 {
1267 purge_count++; 1363 break;
1268 LL_DEBUGS("TextureCache") << "PURGING: " << filename << LL_ENDL;
1269 mFilesToDelete.push_back(filename);
1270 total_size -= entries[idx].mSize;
1271 entries[idx].mSize = 0;
1272 } 1364 }
1273 else 1365
1366 if (purge_entry)
1274 { 1367 {
1275 if (next_idx != idx) 1368 purge_count++;
1276 { 1369 LL_DEBUGS("TextureCache") << "PURGING: " << filename << LL_ENDL;
1277 entries[next_idx] = entries[idx]; 1370 LLAPRFile::remove(filename);
1278 } 1371 cache_size -= entries[idx].mBodySize;
1279 ++next_idx; 1372 mTexturesSizeTotal -= entries[idx].mBodySize;
1373 entries[idx].mBodySize = 0;
1374 mTexturesSizeMap.erase(entries[idx].mID);
1280 } 1375 }
1281 } 1376 }
1282 num_entries = next_idx;
1283 1377
1284 mTimeLastFileDelete.reset(); 1378 LL_DEBUGS("TextureCache") << "TEXTURE CACHE: Writing Entries: " << num_entries << LL_ENDL;
1285 1379
1286 LL_DEBUGS("TextureCache") << "TEXTURE CACHE: Writing Entries: " 1380 writeEntriesAndClose(entries);
1287 << num_entries << " (" << num_entries*sizeof(Entry)/1024 << "KB)"
1288 << LL_ENDL;
1289
1290 LLAPRFile::remove(mTexturesDirEntriesFileName);
1291 LLAPRFile::writeEx(mTexturesDirEntriesFileName,
1292 (U8*)&entries[0], 0, num_entries*sizeof(Entry));
1293
1294 mTexturesSizeTotal = 0;
1295 mTexturesSizeMap.clear();
1296 for (S32 idx=0; idx<num_entries; idx++)
1297 {
1298 mTexturesSizeMap[entries[idx].mID] = entries[idx].mSize;
1299 mTexturesSizeTotal += entries[idx].mSize;
1300 }
1301 llassert(mTexturesSizeTotal == total_size);
1302 1381
1303 delete[] entries;
1304
1305 // *FIX:Mani - watchdog back on. 1382 // *FIX:Mani - watchdog back on.
1306 LLAppViewer::instance()->resumeMainloopTimeout(); 1383 LLAppViewer::instance()->resumeMainloopTimeout();
1307 1384
1308 LL_INFOS("TextureCache") << "TEXTURE CACHE:" 1385 LL_INFOS("TextureCache") << "TEXTURE CACHE:"
1309 << " PURGED: " << purge_count 1386 << " PURGED: " << purge_count
1310 << " ENTRIES: " << num_entries 1387 << " ENTRIES: " << num_entries
1311 << " CACHE SIZE: " << total_size/1024/1024 << " MB" 1388 << " CACHE SIZE: " << mTexturesSizeTotal / 1024*1024 << " MB"
1312 << llendl; 1389 << llendl;
1313} 1390}
1314 1391
1315
1316void LLTextureCache::purgeTextureFilesTimeSliced(BOOL force_all)
1317{
1318 LLMutexLock lock(&mHeaderMutex);
1319
1320 F32 delay_between_passes = 1.0f; // seconds
1321 F32 max_time_per_pass = 0.1f; // seconds
1322
1323 if (!force_all && mTimeLastFileDelete.getElapsedTimeF32() <= delay_between_passes)
1324 {
1325 return;
1326 }
1327
1328 LLTimer timer;
1329 S32 howmany = 0;
1330
1331 if (mFilesToDelete.size() > 0)
1332 {
1333 llinfos << "TEXTURE CACHE: " << mFilesToDelete.size() << " files scheduled for deletion" << llendl;
1334 }
1335
1336 for (LLTextureCache::filename_list_t::iterator iter = mFilesToDelete.begin(); iter!=mFilesToDelete.end(); )
1337 {
1338 LLTextureCache::filename_list_t::iterator iter2 = iter++;
1339 LLAPRFile::remove(*iter2);
1340 mFilesToDelete.erase(iter2);
1341 howmany++;
1342
1343 if (!force_all && timer.getElapsedTimeF32() > max_time_per_pass)
1344 {
1345 break;
1346 }
1347 }
1348
1349 if (!mFilesToDelete.empty())
1350 {
1351 llinfos << "TEXTURE CACHE: "<< howmany << " files deleted ("
1352 << mFilesToDelete.size() << " files left for next pass)"
1353 << llendl;
1354 }
1355
1356 mTimeLastFileDelete.reset();
1357}
1358
1359
1360
1361////////////////////////////////////////////////////////////////////////////// 1392//////////////////////////////////////////////////////////////////////////////
1362 1393
1363// call lockWorkers() first! 1394// call lockWorkers() first!
@@ -1384,75 +1415,39 @@ LLTextureCacheWorker* LLTextureCache::getWriter(handle_t handle)
1384} 1415}
1385 1416
1386////////////////////////////////////////////////////////////////////////////// 1417//////////////////////////////////////////////////////////////////////////////
1387
1388// Called from work thread 1418// Called from work thread
1389S32 LLTextureCache::getHeaderCacheEntry(const LLUUID& id, bool touch, S32* imagesize)
1390{
1391 bool retry = false;
1392 S32 idx = -1;
1393 1419
1420// Reads imagesize from the header, updates timestamp
1421S32 LLTextureCache::getHeaderCacheEntry(const LLUUID& id, S32& imagesize)
1422{
1423 LLMutexLock lock(&mHeaderMutex);
1424 Entry entry;
1425 S32 idx = openAndReadEntry(id, entry, false);
1426 if (idx >= 0)
1394 { 1427 {
1395 LLMutexLock lock(&mHeaderMutex); 1428 imagesize = entry.mImageSize;
1396 id_map_t::iterator iter = mHeaderIDMap.find(id); 1429 writeEntryAndClose(idx, entry); // updates time
1397 if (iter != mHeaderIDMap.end()) 1430 }
1398 { 1431 return idx;
1399 idx = iter->second; 1432}
1400 }
1401 else if (touch && !mReadOnly)
1402 {
1403 if (mHeaderEntriesInfo.mEntries < sCacheMaxEntries)
1404 {
1405 // Add an entry
1406 idx = mHeaderEntriesInfo.mEntries++;
1407 mHeaderIDMap[id] = idx;
1408 // Update Info
1409 LLAPRFile::writeEx(mHeaderEntriesFileName,
1410 (U8*)&mHeaderEntriesInfo, 0, sizeof(EntriesInfo));
1411 }
1412 else if (!mLRU.empty())
1413 {
1414 idx = mLRU.begin()->first; // will be erased below
1415 const LLUUID& oldid = mLRU.begin()->second;
1416 mHeaderIDMap.erase(oldid);
1417 mTexturesSizeMap.erase(oldid);
1418 mHeaderIDMap[id] = idx;
1419 }
1420 else
1421 {
1422 idx = -1;
1423 retry = true;
1424 }
1425 }
1426 if (idx >= 0)
1427 {
1428 if (touch && !mReadOnly)
1429 {
1430 // Update the lru entry
1431 mLRU.erase(idx);
1432 llassert_always(imagesize && *imagesize > 0);
1433 Entry* entry = new Entry(id, *imagesize, time(NULL));
1434 S32 offset = sizeof(EntriesInfo) + idx * sizeof(Entry);
1435 LLAPRFile::writeEx(mHeaderEntriesFileName,
1436 (U8*)entry, offset, sizeof(Entry));
1437 delete entry;
1438 }
1439 else if (imagesize)
1440 {
1441 // Get the image size
1442 Entry entry;
1443 S32 offset = sizeof(EntriesInfo) + idx * sizeof(Entry);
1444 1433
1445 LLAPRFile::readEx(mHeaderEntriesFileName, 1434// Writes imagesize to the header, updates timestamp
1446 (U8*)&entry, offset, sizeof(Entry)); 1435S32 LLTextureCache::setHeaderCacheEntry(const LLUUID& id, S32 imagesize)
1447 *imagesize = entry.mSize; 1436{
1448 } 1437 LLMutexLock lock(&mHeaderMutex);
1449 } 1438 llassert_always(imagesize >= 0);
1439 Entry entry;
1440 S32 idx = openAndReadEntry(id, entry, true);
1441 if (idx >= 0)
1442 {
1443 entry.mImageSize = imagesize;
1444 writeEntryAndClose(idx, entry);
1450 } 1445 }
1451 if (retry) 1446 else // retry
1452 { 1447 {
1453 readHeaderCache(); // updates the lru 1448 readHeaderCache(); // We couldn't write an entry, so refresh the LRU
1454 llassert_always(!mLRU.empty() || mHeaderEntriesInfo.mEntries < sCacheMaxEntries); 1449 llassert_always(!mLRU.empty() || mHeaderEntriesInfo.mEntries < sCacheMaxEntries);
1455 idx = getHeaderCacheEntry(id, touch, imagesize); // assert above ensures no inf. recursion 1450 idx = setHeaderCacheEntry(id, imagesize); // assert above ensures no inf. recursion
1456 } 1451 }
1457 return idx; 1452 return idx;
1458} 1453}
@@ -1468,8 +1463,8 @@ LLTextureCache::handle_t LLTextureCache::readFromCache(const std::string& filena
1468 // so let the thread handle it 1463 // so let the thread handle it
1469 LLMutexLock lock(&mWorkersMutex); 1464 LLMutexLock lock(&mWorkersMutex);
1470 LLTextureCacheWorker* worker = new LLTextureCacheLocalFileWorker(this, priority, filename, id, 1465 LLTextureCacheWorker* worker = new LLTextureCacheLocalFileWorker(this, priority, filename, id,
1471 NULL, size, offset, 0, 1466 NULL, size, offset, 0,
1472 responder); 1467 responder);
1473 handle_t handle = worker->read(); 1468 handle_t handle = worker->read();
1474 mReaders[handle] = worker; 1469 mReaders[handle] = worker;
1475 return handle; 1470 return handle;
@@ -1482,8 +1477,8 @@ LLTextureCache::handle_t LLTextureCache::readFromCache(const LLUUID& id, U32 pri
1482 // so let the thread handle it 1477 // so let the thread handle it
1483 LLMutexLock lock(&mWorkersMutex); 1478 LLMutexLock lock(&mWorkersMutex);
1484 LLTextureCacheWorker* worker = new LLTextureCacheRemoteWorker(this, priority, id, 1479 LLTextureCacheWorker* worker = new LLTextureCacheRemoteWorker(this, priority, id,
1485 NULL, size, offset, 0, 1480 NULL, size, offset,
1486 responder); 1481 0, responder);
1487 handle_t handle = worker->read(); 1482 handle_t handle = worker->read();
1488 mReaders[handle] = worker; 1483 mReaders[handle] = worker;
1489 return handle; 1484 return handle;
@@ -1494,7 +1489,7 @@ bool LLTextureCache::readComplete(handle_t handle, bool abort)
1494{ 1489{
1495 lockWorkers(); 1490 lockWorkers();
1496 handle_map_t::iterator iter = mReaders.find(handle); 1491 handle_map_t::iterator iter = mReaders.find(handle);
1497 llassert_always(iter != mReaders.end()); 1492 llassert_always(iter != mReaders.end() || abort);
1498 LLTextureCacheWorker* worker = iter->second; 1493 LLTextureCacheWorker* worker = iter->second;
1499 bool res = worker->complete(); 1494 bool res = worker->complete();
1500 if (res || abort) 1495 if (res || abort)
@@ -1528,14 +1523,10 @@ LLTextureCache::handle_t LLTextureCache::writeToCache(const LLUUID& id, U32 prio
1528 purgeTextures(false); 1523 purgeTextures(false);
1529 mDoPurge = FALSE; 1524 mDoPurge = FALSE;
1530 } 1525 }
1531
1532 purgeTextureFilesTimeSliced(); // purge textures from cache in a non-hiccup-way
1533
1534
1535 LLMutexLock lock(&mWorkersMutex); 1526 LLMutexLock lock(&mWorkersMutex);
1536 LLTextureCacheWorker* worker = new LLTextureCacheRemoteWorker(this, priority, id, 1527 LLTextureCacheWorker* worker = new LLTextureCacheRemoteWorker(this, priority, id,
1537 data, datasize, 0, 1528 data, datasize, 0,
1538 imagesize, responder); 1529 imagesize, responder);
1539 handle_t handle = worker->write(); 1530 handle_t handle = worker->write();
1540 mWriters[handle] = worker; 1531 mWriters[handle] = worker;
1541 return handle; 1532 return handle;
@@ -1581,24 +1572,17 @@ void LLTextureCache::addCompleted(Responder* responder, bool success)
1581 1572
1582bool LLTextureCache::removeHeaderCacheEntry(const LLUUID& id) 1573bool LLTextureCache::removeHeaderCacheEntry(const LLUUID& id)
1583{ 1574{
1584 if (mReadOnly) 1575 if (!mReadOnly)
1585 {
1586 return false;
1587 }
1588 LLMutexLock lock(&mHeaderMutex);
1589 id_map_t::iterator iter = mHeaderIDMap.find(id);
1590 if (iter != mHeaderIDMap.end())
1591 { 1576 {
1592 S32 idx = iter->second; 1577 LLMutexLock lock(&mHeaderMutex);
1578 Entry entry;
1579 S32 idx = openAndReadEntry(id, entry, false);
1593 if (idx >= 0) 1580 if (idx >= 0)
1594 { 1581 {
1595 Entry* entry = new Entry(id, -1, time(NULL)); 1582 entry.mImageSize = -1;
1596 S32 offset = sizeof(EntriesInfo) + idx * sizeof(Entry); 1583 entry.mBodySize = 0;
1597 1584 writeEntryAndClose(idx, entry);
1598 LLAPRFile::writeEx(mHeaderEntriesFileName, 1585 mFreeList.insert(idx);
1599 (U8*)entry, offset, sizeof(Entry));
1600 delete entry;
1601 mLRU[idx] = id;
1602 mHeaderIDMap.erase(id); 1586 mHeaderIDMap.erase(id);
1603 mTexturesSizeMap.erase(id); 1587 mTexturesSizeMap.erase(id);
1604 return true; 1588 return true;