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();