/indra/newview/llvocache.cpp

https://bitbucket.org/lindenlab/viewer-beta/ · C++ · 753 lines · 591 code · 103 blank · 59 comment · 96 complexity · edba3597c6e24463bba78b382dd2f77a MD5 · raw file

  1. /**
  2. * @file llvocache.cpp
  3. * @brief Cache of objects on the viewer.
  4. *
  5. * $LicenseInfo:firstyear=2003&license=viewerlgpl$
  6. * Second Life Viewer Source Code
  7. * Copyright (C) 2010, Linden Research, Inc.
  8. *
  9. * This library is free software; you can redistribute it and/or
  10. * modify it under the terms of the GNU Lesser General Public
  11. * License as published by the Free Software Foundation;
  12. * version 2.1 of the License only.
  13. *
  14. * This library is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  17. * Lesser General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU Lesser General Public
  20. * License along with this library; if not, write to the Free Software
  21. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  22. *
  23. * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
  24. * $/LicenseInfo$
  25. */
  26. #include "llviewerprecompiledheaders.h"
  27. #include "llvocache.h"
  28. #include "llerror.h"
  29. #include "llregionhandle.h"
  30. #include "llviewercontrol.h"
  31. BOOL check_read(LLAPRFile* apr_file, void* src, S32 n_bytes)
  32. {
  33. return apr_file->read(src, n_bytes) == n_bytes ;
  34. }
  35. BOOL check_write(LLAPRFile* apr_file, void* src, S32 n_bytes)
  36. {
  37. return apr_file->write(src, n_bytes) == n_bytes ;
  38. }
  39. //---------------------------------------------------------------------------
  40. // LLVOCacheEntry
  41. //---------------------------------------------------------------------------
  42. LLVOCacheEntry::LLVOCacheEntry(U32 local_id, U32 crc, LLDataPackerBinaryBuffer &dp)
  43. :
  44. mLocalID(local_id),
  45. mCRC(crc),
  46. mHitCount(0),
  47. mDupeCount(0),
  48. mCRCChangeCount(0)
  49. {
  50. mBuffer = new U8[dp.getBufferSize()];
  51. mDP.assignBuffer(mBuffer, dp.getBufferSize());
  52. mDP = dp;
  53. }
  54. LLVOCacheEntry::LLVOCacheEntry()
  55. :
  56. mLocalID(0),
  57. mCRC(0),
  58. mHitCount(0),
  59. mDupeCount(0),
  60. mCRCChangeCount(0),
  61. mBuffer(NULL)
  62. {
  63. mDP.assignBuffer(mBuffer, 0);
  64. }
  65. LLVOCacheEntry::LLVOCacheEntry(LLAPRFile* apr_file)
  66. : mBuffer(NULL)
  67. {
  68. S32 size = -1;
  69. BOOL success;
  70. mDP.assignBuffer(mBuffer, 0);
  71. success = check_read(apr_file, &mLocalID, sizeof(U32));
  72. if(success)
  73. {
  74. success = check_read(apr_file, &mCRC, sizeof(U32));
  75. }
  76. if(success)
  77. {
  78. success = check_read(apr_file, &mHitCount, sizeof(S32));
  79. }
  80. if(success)
  81. {
  82. success = check_read(apr_file, &mDupeCount, sizeof(S32));
  83. }
  84. if(success)
  85. {
  86. success = check_read(apr_file, &mCRCChangeCount, sizeof(S32));
  87. }
  88. if(success)
  89. {
  90. success = check_read(apr_file, &size, sizeof(S32));
  91. // Corruption in the cache entries
  92. if ((size > 10000) || (size < 1))
  93. {
  94. // We've got a bogus size, skip reading it.
  95. // We won't bother seeking, because the rest of this file
  96. // is likely bogus, and will be tossed anyway.
  97. llwarns << "Bogus cache entry, size " << size << ", aborting!" << llendl;
  98. success = FALSE;
  99. }
  100. }
  101. if(success && size > 0)
  102. {
  103. mBuffer = new U8[size];
  104. success = check_read(apr_file, mBuffer, size);
  105. if(success)
  106. {
  107. mDP.assignBuffer(mBuffer, size);
  108. }
  109. else
  110. {
  111. delete[] mBuffer ;
  112. mBuffer = NULL ;
  113. }
  114. }
  115. if(!success)
  116. {
  117. mLocalID = 0;
  118. mCRC = 0;
  119. mHitCount = 0;
  120. mDupeCount = 0;
  121. mCRCChangeCount = 0;
  122. mBuffer = NULL;
  123. }
  124. }
  125. LLVOCacheEntry::~LLVOCacheEntry()
  126. {
  127. mDP.freeBuffer();
  128. }
  129. // New CRC means the object has changed.
  130. void LLVOCacheEntry::assignCRC(U32 crc, LLDataPackerBinaryBuffer &dp)
  131. {
  132. if ( (mCRC != crc)
  133. ||(mDP.getBufferSize() == 0))
  134. {
  135. mCRC = crc;
  136. mHitCount = 0;
  137. mCRCChangeCount++;
  138. mDP.freeBuffer();
  139. mBuffer = new U8[dp.getBufferSize()];
  140. mDP.assignBuffer(mBuffer, dp.getBufferSize());
  141. mDP = dp;
  142. }
  143. }
  144. LLDataPackerBinaryBuffer *LLVOCacheEntry::getDP(U32 crc)
  145. {
  146. if ( (mCRC != crc)
  147. ||(mDP.getBufferSize() == 0))
  148. {
  149. //llinfos << "Not getting cache entry, invalid!" << llendl;
  150. return NULL;
  151. }
  152. mHitCount++;
  153. return &mDP;
  154. }
  155. void LLVOCacheEntry::recordHit()
  156. {
  157. mHitCount++;
  158. }
  159. void LLVOCacheEntry::dump() const
  160. {
  161. llinfos << "local " << mLocalID
  162. << " crc " << mCRC
  163. << " hits " << mHitCount
  164. << " dupes " << mDupeCount
  165. << " change " << mCRCChangeCount
  166. << llendl;
  167. }
  168. BOOL LLVOCacheEntry::writeToFile(LLAPRFile* apr_file) const
  169. {
  170. BOOL success;
  171. success = check_write(apr_file, (void*)&mLocalID, sizeof(U32));
  172. if(success)
  173. {
  174. success = check_write(apr_file, (void*)&mCRC, sizeof(U32));
  175. }
  176. if(success)
  177. {
  178. success = check_write(apr_file, (void*)&mHitCount, sizeof(S32));
  179. }
  180. if(success)
  181. {
  182. success = check_write(apr_file, (void*)&mDupeCount, sizeof(S32));
  183. }
  184. if(success)
  185. {
  186. success = check_write(apr_file, (void*)&mCRCChangeCount, sizeof(S32));
  187. }
  188. if(success)
  189. {
  190. S32 size = mDP.getBufferSize();
  191. success = check_write(apr_file, (void*)&size, sizeof(S32));
  192. if(success)
  193. {
  194. success = check_write(apr_file, (void*)mBuffer, size);
  195. }
  196. }
  197. return success ;
  198. }
  199. //-------------------------------------------------------------------
  200. //LLVOCache
  201. //-------------------------------------------------------------------
  202. // Format string used to construct filename for the object cache
  203. static const char OBJECT_CACHE_FILENAME[] = "objects_%d_%d.slc";
  204. const U32 MAX_NUM_OBJECT_ENTRIES = 128 ;
  205. const U32 MIN_ENTRIES_TO_PURGE = 16 ;
  206. const U32 INVALID_TIME = 0 ;
  207. const char* object_cache_dirname = "objectcache";
  208. const char* header_filename = "object.cache";
  209. LLVOCache* LLVOCache::sInstance = NULL;
  210. //static
  211. LLVOCache* LLVOCache::getInstance()
  212. {
  213. if(!sInstance)
  214. {
  215. sInstance = new LLVOCache() ;
  216. }
  217. return sInstance ;
  218. }
  219. //static
  220. BOOL LLVOCache::hasInstance()
  221. {
  222. return sInstance != NULL ;
  223. }
  224. //static
  225. void LLVOCache::destroyClass()
  226. {
  227. if(sInstance)
  228. {
  229. delete sInstance ;
  230. sInstance = NULL ;
  231. }
  232. }
  233. LLVOCache::LLVOCache():
  234. mInitialized(FALSE),
  235. mReadOnly(TRUE),
  236. mNumEntries(0),
  237. mCacheSize(1)
  238. {
  239. mEnabled = gSavedSettings.getBOOL("ObjectCacheEnabled");
  240. mLocalAPRFilePoolp = new LLVolatileAPRPool() ;
  241. }
  242. LLVOCache::~LLVOCache()
  243. {
  244. if(mEnabled)
  245. {
  246. writeCacheHeader();
  247. clearCacheInMemory();
  248. }
  249. delete mLocalAPRFilePoolp;
  250. }
  251. void LLVOCache::setDirNames(ELLPath location)
  252. {
  253. mHeaderFileName = gDirUtilp->getExpandedFilename(location, object_cache_dirname, header_filename);
  254. mObjectCacheDirName = gDirUtilp->getExpandedFilename(location, object_cache_dirname);
  255. }
  256. void LLVOCache::initCache(ELLPath location, U32 size, U32 cache_version)
  257. {
  258. if(!mEnabled)
  259. {
  260. llwarns << "Not initializing cache: Cache is currently disabled." << llendl;
  261. return ;
  262. }
  263. if(mInitialized)
  264. {
  265. llwarns << "Cache already initialized." << llendl;
  266. return ;
  267. }
  268. mInitialized = TRUE ;
  269. setDirNames(location);
  270. if (!mReadOnly)
  271. {
  272. LLFile::mkdir(mObjectCacheDirName);
  273. }
  274. mCacheSize = llclamp(size, MIN_ENTRIES_TO_PURGE, MAX_NUM_OBJECT_ENTRIES);
  275. mMetaInfo.mVersion = cache_version;
  276. readCacheHeader();
  277. if(mMetaInfo.mVersion != cache_version)
  278. {
  279. mMetaInfo.mVersion = cache_version ;
  280. if(mReadOnly) //disable cache
  281. {
  282. clearCacheInMemory();
  283. }
  284. else //delete the current cache if the format does not match.
  285. {
  286. removeCache();
  287. }
  288. }
  289. }
  290. void LLVOCache::removeCache(ELLPath location)
  291. {
  292. if(mReadOnly)
  293. {
  294. llwarns << "Not removing cache at " << location << ": Cache is currently in read-only mode." << llendl;
  295. return ;
  296. }
  297. llinfos << "about to remove the object cache due to settings." << llendl ;
  298. std::string mask = "*";
  299. std::string cache_dir = gDirUtilp->getExpandedFilename(location, object_cache_dirname);
  300. llinfos << "Removing cache at " << cache_dir << llendl;
  301. gDirUtilp->deleteFilesInDir(cache_dir, mask); //delete all files
  302. LLFile::rmdir(cache_dir);
  303. clearCacheInMemory();
  304. mInitialized = FALSE ;
  305. }
  306. void LLVOCache::removeCache()
  307. {
  308. llassert_always(mInitialized) ;
  309. if(mReadOnly)
  310. {
  311. llwarns << "Not clearing object cache: Cache is currently in read-only mode." << llendl;
  312. return ;
  313. }
  314. llinfos << "about to remove the object cache due to some error." << llendl ;
  315. std::string mask = "*";
  316. llinfos << "Removing cache at " << mObjectCacheDirName << llendl;
  317. gDirUtilp->deleteFilesInDir(mObjectCacheDirName, mask);
  318. clearCacheInMemory() ;
  319. writeCacheHeader();
  320. }
  321. void LLVOCache::removeEntry(HeaderEntryInfo* entry)
  322. {
  323. llassert_always(mInitialized) ;
  324. if(mReadOnly)
  325. {
  326. return ;
  327. }
  328. if(!entry)
  329. {
  330. return ;
  331. }
  332. header_entry_queue_t::iterator iter = mHeaderEntryQueue.find(entry) ;
  333. if(iter != mHeaderEntryQueue.end())
  334. {
  335. mHandleEntryMap.erase(entry->mHandle) ;
  336. mHeaderEntryQueue.erase(iter) ;
  337. removeFromCache(entry) ;
  338. delete entry ;
  339. mNumEntries = mHandleEntryMap.size() ;
  340. }
  341. }
  342. void LLVOCache::removeEntry(U64 handle)
  343. {
  344. handle_entry_map_t::iterator iter = mHandleEntryMap.find(handle) ;
  345. if(iter == mHandleEntryMap.end()) //no cache
  346. {
  347. return ;
  348. }
  349. HeaderEntryInfo* entry = iter->second ;
  350. removeEntry(entry) ;
  351. }
  352. void LLVOCache::clearCacheInMemory()
  353. {
  354. if(!mHeaderEntryQueue.empty())
  355. {
  356. for(header_entry_queue_t::iterator iter = mHeaderEntryQueue.begin(); iter != mHeaderEntryQueue.end(); ++iter)
  357. {
  358. delete *iter ;
  359. }
  360. mHeaderEntryQueue.clear();
  361. mHandleEntryMap.clear();
  362. mNumEntries = 0 ;
  363. }
  364. }
  365. void LLVOCache::getObjectCacheFilename(U64 handle, std::string& filename)
  366. {
  367. U32 region_x, region_y;
  368. grid_from_region_handle(handle, &region_x, &region_y);
  369. filename = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, object_cache_dirname,
  370. llformat(OBJECT_CACHE_FILENAME, region_x, region_y));
  371. return ;
  372. }
  373. void LLVOCache::removeFromCache(HeaderEntryInfo* entry)
  374. {
  375. if(mReadOnly)
  376. {
  377. llwarns << "Not removing cache for handle " << entry->mHandle << ": Cache is currently in read-only mode." << llendl;
  378. return ;
  379. }
  380. std::string filename;
  381. getObjectCacheFilename(entry->mHandle, filename);
  382. LLAPRFile::remove(filename, mLocalAPRFilePoolp);
  383. entry->mTime = INVALID_TIME ;
  384. updateEntry(entry) ; //update the head file.
  385. }
  386. void LLVOCache::readCacheHeader()
  387. {
  388. if(!mEnabled)
  389. {
  390. llwarns << "Not reading cache header: Cache is currently disabled." << llendl;
  391. return;
  392. }
  393. //clear stale info.
  394. clearCacheInMemory();
  395. bool success = true ;
  396. if (LLAPRFile::isExist(mHeaderFileName, mLocalAPRFilePoolp))
  397. {
  398. LLAPRFile apr_file(mHeaderFileName, APR_READ|APR_BINARY, mLocalAPRFilePoolp);
  399. //read the meta element
  400. success = check_read(&apr_file, &mMetaInfo, sizeof(HeaderMetaInfo)) ;
  401. if(success)
  402. {
  403. HeaderEntryInfo* entry = NULL ;
  404. mNumEntries = 0 ;
  405. U32 num_read = 0 ;
  406. while(num_read++ < MAX_NUM_OBJECT_ENTRIES)
  407. {
  408. if(!entry)
  409. {
  410. entry = new HeaderEntryInfo() ;
  411. }
  412. success = check_read(&apr_file, entry, sizeof(HeaderEntryInfo));
  413. if(!success) //failed
  414. {
  415. llwarns << "Error reading cache header entry. (entry_index=" << mNumEntries << ")" << llendl;
  416. delete entry ;
  417. entry = NULL ;
  418. break ;
  419. }
  420. else if(entry->mTime == INVALID_TIME)
  421. {
  422. continue ; //an empty entry
  423. }
  424. entry->mIndex = mNumEntries++ ;
  425. mHeaderEntryQueue.insert(entry) ;
  426. mHandleEntryMap[entry->mHandle] = entry ;
  427. entry = NULL ;
  428. }
  429. if(entry)
  430. {
  431. delete entry ;
  432. }
  433. }
  434. //---------
  435. //debug code
  436. //----------
  437. //std::string name ;
  438. //for(header_entry_queue_t::iterator iter = mHeaderEntryQueue.begin() ; success && iter != mHeaderEntryQueue.end(); ++iter)
  439. //{
  440. // getObjectCacheFilename((*iter)->mHandle, name) ;
  441. // llinfos << name << llendl ;
  442. //}
  443. //-----------
  444. }
  445. else
  446. {
  447. writeCacheHeader() ;
  448. }
  449. if(!success)
  450. {
  451. removeCache() ; //failed to read header, clear the cache
  452. }
  453. else if(mNumEntries >= mCacheSize)
  454. {
  455. purgeEntries(mCacheSize) ;
  456. }
  457. return ;
  458. }
  459. void LLVOCache::writeCacheHeader()
  460. {
  461. if (!mEnabled)
  462. {
  463. llwarns << "Not writing cache header: Cache is currently disabled." << llendl;
  464. return;
  465. }
  466. if(mReadOnly)
  467. {
  468. llwarns << "Not writing cache header: Cache is currently in read-only mode." << llendl;
  469. return;
  470. }
  471. bool success = true ;
  472. {
  473. LLAPRFile apr_file(mHeaderFileName, APR_CREATE|APR_WRITE|APR_BINARY, mLocalAPRFilePoolp);
  474. //write the meta element
  475. success = check_write(&apr_file, &mMetaInfo, sizeof(HeaderMetaInfo)) ;
  476. mNumEntries = 0 ;
  477. for(header_entry_queue_t::iterator iter = mHeaderEntryQueue.begin() ; success && iter != mHeaderEntryQueue.end(); ++iter)
  478. {
  479. (*iter)->mIndex = mNumEntries++ ;
  480. success = check_write(&apr_file, (void*)*iter, sizeof(HeaderEntryInfo));
  481. }
  482. mNumEntries = mHeaderEntryQueue.size() ;
  483. if(success && mNumEntries < MAX_NUM_OBJECT_ENTRIES)
  484. {
  485. HeaderEntryInfo* entry = new HeaderEntryInfo() ;
  486. entry->mTime = INVALID_TIME ;
  487. for(S32 i = mNumEntries ; success && i < MAX_NUM_OBJECT_ENTRIES ; i++)
  488. {
  489. //fill the cache with the default entry.
  490. success = check_write(&apr_file, entry, sizeof(HeaderEntryInfo)) ;
  491. }
  492. delete entry ;
  493. }
  494. }
  495. if(!success)
  496. {
  497. clearCacheInMemory() ;
  498. mReadOnly = TRUE ; //disable the cache.
  499. }
  500. return ;
  501. }
  502. BOOL LLVOCache::updateEntry(const HeaderEntryInfo* entry)
  503. {
  504. LLAPRFile apr_file(mHeaderFileName, APR_WRITE|APR_BINARY, mLocalAPRFilePoolp);
  505. apr_file.seek(APR_SET, entry->mIndex * sizeof(HeaderEntryInfo) + sizeof(HeaderMetaInfo)) ;
  506. return check_write(&apr_file, (void*)entry, sizeof(HeaderEntryInfo)) ;
  507. }
  508. void LLVOCache::readFromCache(U64 handle, const LLUUID& id, LLVOCacheEntry::vocache_entry_map_t& cache_entry_map)
  509. {
  510. if(!mEnabled)
  511. {
  512. llwarns << "Not reading cache for handle " << handle << "): Cache is currently disabled." << llendl;
  513. return ;
  514. }
  515. llassert_always(mInitialized);
  516. handle_entry_map_t::iterator iter = mHandleEntryMap.find(handle) ;
  517. if(iter == mHandleEntryMap.end()) //no cache
  518. {
  519. llwarns << "No handle map entry for " << handle << llendl;
  520. return ;
  521. }
  522. bool success = true ;
  523. {
  524. std::string filename;
  525. getObjectCacheFilename(handle, filename);
  526. LLAPRFile apr_file(filename, APR_READ|APR_BINARY, mLocalAPRFilePoolp);
  527. LLUUID cache_id ;
  528. success = check_read(&apr_file, cache_id.mData, UUID_BYTES) ;
  529. if(success)
  530. {
  531. if(cache_id != id)
  532. {
  533. llinfos << "Cache ID doesn't match for this region, discarding"<< llendl;
  534. success = false ;
  535. }
  536. if(success)
  537. {
  538. S32 num_entries;
  539. success = check_read(&apr_file, &num_entries, sizeof(S32)) ;
  540. if(success)
  541. {
  542. for (S32 i = 0; i < num_entries; i++)
  543. {
  544. LLVOCacheEntry* entry = new LLVOCacheEntry(&apr_file);
  545. if (!entry->getLocalID())
  546. {
  547. llwarns << "Aborting cache file load for " << filename << ", cache file corruption!" << llendl;
  548. delete entry ;
  549. success = false ;
  550. break ;
  551. }
  552. cache_entry_map[entry->getLocalID()] = entry;
  553. }
  554. }
  555. }
  556. }
  557. }
  558. if(!success)
  559. {
  560. if(cache_entry_map.empty())
  561. {
  562. removeEntry(iter->second) ;
  563. }
  564. }
  565. return ;
  566. }
  567. void LLVOCache::purgeEntries(U32 size)
  568. {
  569. while(mHeaderEntryQueue.size() > size)
  570. {
  571. header_entry_queue_t::iterator iter = mHeaderEntryQueue.begin() ;
  572. HeaderEntryInfo* entry = *iter ;
  573. mHandleEntryMap.erase(entry->mHandle);
  574. mHeaderEntryQueue.erase(iter) ;
  575. removeFromCache(entry) ;
  576. delete entry;
  577. }
  578. mNumEntries = mHandleEntryMap.size() ;
  579. }
  580. void LLVOCache::writeToCache(U64 handle, const LLUUID& id, const LLVOCacheEntry::vocache_entry_map_t& cache_entry_map, BOOL dirty_cache)
  581. {
  582. if(!mEnabled)
  583. {
  584. llwarns << "Not writing cache for handle " << handle << "): Cache is currently disabled." << llendl;
  585. return ;
  586. }
  587. llassert_always(mInitialized);
  588. if(mReadOnly)
  589. {
  590. llwarns << "Not writing cache for handle " << handle << "): Cache is currently in read-only mode." << llendl;
  591. return ;
  592. }
  593. HeaderEntryInfo* entry;
  594. handle_entry_map_t::iterator iter = mHandleEntryMap.find(handle) ;
  595. if(iter == mHandleEntryMap.end()) //new entry
  596. {
  597. if(mNumEntries >= mCacheSize - 1)
  598. {
  599. purgeEntries(mCacheSize - 1) ;
  600. }
  601. entry = new HeaderEntryInfo();
  602. entry->mHandle = handle ;
  603. entry->mTime = time(NULL) ;
  604. entry->mIndex = mNumEntries++;
  605. mHeaderEntryQueue.insert(entry) ;
  606. mHandleEntryMap[handle] = entry ;
  607. }
  608. else
  609. {
  610. // Update access time.
  611. entry = iter->second ;
  612. //resort
  613. mHeaderEntryQueue.erase(entry) ;
  614. entry->mTime = time(NULL) ;
  615. mHeaderEntryQueue.insert(entry) ;
  616. }
  617. //update cache header
  618. if(!updateEntry(entry))
  619. {
  620. llwarns << "Failed to update cache header index " << entry->mIndex << ". handle = " << handle << llendl;
  621. return ; //update failed.
  622. }
  623. if(!dirty_cache)
  624. {
  625. llwarns << "Skipping write to cache for handle " << handle << ": cache not dirty" << llendl;
  626. return ; //nothing changed, no need to update.
  627. }
  628. //write to cache file
  629. bool success = true ;
  630. {
  631. std::string filename;
  632. getObjectCacheFilename(handle, filename);
  633. LLAPRFile apr_file(filename, APR_CREATE|APR_WRITE|APR_BINARY, mLocalAPRFilePoolp);
  634. success = check_write(&apr_file, (void*)id.mData, UUID_BYTES) ;
  635. if(success)
  636. {
  637. S32 num_entries = cache_entry_map.size() ;
  638. success = check_write(&apr_file, &num_entries, sizeof(S32));
  639. for (LLVOCacheEntry::vocache_entry_map_t::const_iterator iter = cache_entry_map.begin(); success && iter != cache_entry_map.end(); ++iter)
  640. {
  641. success = iter->second->writeToFile(&apr_file) ;
  642. }
  643. }
  644. }
  645. if(!success)
  646. {
  647. removeEntry(entry) ;
  648. }
  649. return ;
  650. }