diff --git a/indra/newview/fsappviewerwin32.cpp b/indra/newview/fsappviewerwin32.cpp new file mode 100644 index 0000000000..3daaf17f0e --- /dev/null +++ b/indra/newview/fsappviewerwin32.cpp @@ -0,0 +1,110 @@ +// Thread to purge old texture cache in the background. +// The cache dir will be search for directories named *.old_texturecache, then each of this directories +// will be deleted. +// The thread will be started each time the viewer starts, just in case there is directories so huge, +// the user quit the viewer before the old cache was fully cleared. + +void deleteFilesInDirectory( std::wstring aDir ) +{ + if( aDir == L"." || aDir == L".." || aDir.empty() ) + return; + + if( aDir[ aDir.size() -1 ] != '\\' || aDir[ aDir.size() -1 ] != '/' ) + aDir += L"\\"; + + WIN32_FIND_DATA oFindData; + HANDLE hFindHandle = ::FindFirstFile( (aDir + L"*.*").c_str(), &oFindData ); + + if( INVALID_HANDLE_VALUE == hFindHandle ) + return; + + do + { + if( ! (oFindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) ) + { + std::wstring strFile = aDir + oFindData.cFileName; + if( oFindData.dwFileAttributes & FILE_ATTRIBUTE_READONLY ) + ::SetFileAttributes( strFile.c_str(), FILE_ATTRIBUTE_NORMAL ); + + ::DeleteFile( ( aDir + oFindData.cFileName ).c_str() ); + } + } while( ::FindNextFile( hFindHandle, &oFindData ) ); + + ::FindClose( hFindHandle ); +} + +void deleteCacheDirectory( std::wstring aDir ) +{ + if( aDir == L"." || aDir == L".." || aDir.empty() ) + return; + + if( aDir[ aDir.size() -1 ] != '\\' || aDir[ aDir.size() -1 ] != '/' ) + aDir += L"\\"; + + wchar_t aCacheDirs[] = L"0123456789abcdef"; + + for( int i = 0; i < _countof( aCacheDirs ); ++i ) + { + deleteFilesInDirectory( aDir + aCacheDirs[i] ); + ::RemoveDirectory( (aDir + aCacheDirs[i]).c_str() ); + } + + deleteFilesInDirectory( aDir ); + ::RemoveDirectory( aDir.c_str() ); +} + +DWORD WINAPI purgeThread( LPVOID lpParameter ) +{ + wchar_t *pDir = reinterpret_cast< wchar_t* >( lpParameter ); + if( !pDir ) + return 0; + + std::wstring strPath = pDir; + free( pDir ); + + if( strPath.empty() ) + return 0; + + if( strPath[ strPath.size() -1 ] != '\\' || strPath[ strPath.size() -1 ] != '/' ) + strPath += L"\\"; + + WIN32_FIND_DATA oFindData; + HANDLE hFindHandle = ::FindFirstFile( ( strPath + L"*.old_texturecache" ).c_str(), &oFindData ); + + std::vector< std::wstring > vctDirs; + + if( INVALID_HANDLE_VALUE == hFindHandle ) + return 0; + + do + { + if( oFindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) + vctDirs.push_back( strPath + oFindData.cFileName ); + } while( ::FindNextFile( hFindHandle, &oFindData ) ); + + ::FindClose( hFindHandle ); + + for( auto dir : vctDirs ) + deleteCacheDirectory( dir ); + + return 0; +} + +void LLAppViewerWin32::startCachePurge() +{ + if( isSecondInstance() ) + return; + + std::wstring strCacheDir = wstringize( gDirUtilp->getExpandedFilename( LL_PATH_CACHE, "" ) ); + + HANDLE hThread = CreateThread( nullptr, 0, purgeThread, _wcsdup( strCacheDir.c_str() ), 0, nullptr ); + + if( !hThread ) + { + LL_WARNS("CachePurge") << "CreateThread failed: " << GetLastError() << LL_ENDL; + } + else + SetThreadPriority( hThread, THREAD_MODE_BACKGROUND_BEGIN ); +} + +// diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 3a9e2a8c48..0932aa0f89 100755 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -5132,6 +5132,10 @@ bool LLAppViewer::initCache() } // + // For Windows, purging the cache can take an extraordinary amount of time. Rename the cache dir and purge it using another thread. + startCachePurge(); + // + LLSplashScreen::update(LLTrans::getString("StartupInitializingTextureCache")); // Init the texture cache diff --git a/indra/newview/llappviewer.h b/indra/newview/llappviewer.h index dca4fc42b4..1438153873 100755 --- a/indra/newview/llappviewer.h +++ b/indra/newview/llappviewer.h @@ -350,6 +350,11 @@ public: void setSaveSettingsOnExit(bool state) {mSaveSettingsOnExit = state; }; bool mSaveSettingsOnExit; // + +// For Windows, purging the cache can take an extraordinary amount of time. Rename the cache dir and purge it using another thread. +private: + virtual void startCachePurge() {} +// }; // consts from viewer.h diff --git a/indra/newview/llappviewerwin32.cpp b/indra/newview/llappviewerwin32.cpp index 4c8bf190dc..0e0b5855e5 100644 --- a/indra/newview/llappviewerwin32.cpp +++ b/indra/newview/llappviewerwin32.cpp @@ -937,3 +937,5 @@ std::string LLAppViewerWin32::generateSerialNumber() } return serial_md5; } + +#include "fsappviewerwin32.cpp" diff --git a/indra/newview/llappviewerwin32.h b/indra/newview/llappviewerwin32.h index 59d1ddaa3d..afa8b014a6 100644 --- a/indra/newview/llappviewerwin32.h +++ b/indra/newview/llappviewerwin32.h @@ -63,6 +63,11 @@ private: std::string mCmdLine; bool mIsConsoleAllocated; + +// For Windows, purging the cache can take an extraordinary amount of time. Rename the cache dir and purge it using another thread. + virtual void startCachePurge(); +// + }; #endif // LL_LLAPPVIEWERWIN32_H diff --git a/indra/newview/lltexturecache.cpp b/indra/newview/lltexturecache.cpp index bea852ea5b..417d8c49ee 100755 --- a/indra/newview/lltexturecache.cpp +++ b/indra/newview/lltexturecache.cpp @@ -1542,6 +1542,25 @@ void LLTextureCache::purgeAllTextures(bool purge_directories) { if (!mReadOnly) { +// Windows can be really slow deleting a huge texture cache. +// In case of a full purge rename the directory and then purge this using a low priority background thread. +#if LL_WINDOWS + bool bOldPurge = true; + if( purge_directories ) + { + std::string strNewName = mCacheParentDirName + gDirUtilp->getDirDelimiter() + LLUUID::generateNewID().asString() + ".old_texturecache"; + if( LLFile::isdir( mTexturesDirName ) ) + bOldPurge = ( 0 != LLFile::rename( mTexturesDirName, strNewName ) ); + + if( bOldPurge ) + { + LL_WARNS() << "Rename of " << mTexturesDirName << " to " << strNewName << " failed" << LL_ENDL; + } + } + if( !purge_directories || bOldPurge ) +#endif +// + { const char* subdirs = "0123456789abcdef"; std::string delem = gDirUtilp->getDirDelimiter(); std::string mask = "*"; @@ -1565,7 +1584,8 @@ void LLTextureCache::purgeAllTextures(bool purge_directories) { gDirUtilp->deleteFilesInDir(mTexturesDirName, mask); LLFile::rmdir(mTexturesDirName); - } + } + } } mHeaderIDMap.clear(); mTexturesSizeMap.clear();