summaryrefslogtreecommitdiff
path: root/indra/llfilesystem
diff options
context:
space:
mode:
authorAndrey Lihatskiy <alihatskiy@productengine.com>2024-10-17 16:56:21 +0300
committerGitHub <noreply@github.com>2024-10-17 16:56:21 +0300
commit0ef7a9b39cf72da1211039ab22bdf8f9f6a2c984 (patch)
tree6f51ef179497265b5bff2a355471ae5dc9643ad2 /indra/llfilesystem
parent9e24b300d02e5627ea0d304d412cb683ec2de3a4 (diff)
parentd3d349ae0f17a72481f30b9354b9367b1cd3b639 (diff)
Merge pull request #2856 from secondlife/marchcat/c-develop
Develop → Maint C sync
Diffstat (limited to 'indra/llfilesystem')
-rw-r--r--indra/llfilesystem/lldir.cpp25
-rw-r--r--indra/llfilesystem/lldir.h3
-rw-r--r--indra/llfilesystem/lldir_linux.cpp4
-rw-r--r--indra/llfilesystem/lldir_mac.cpp2
-rw-r--r--indra/llfilesystem/lldir_mac.h2
-rw-r--r--indra/llfilesystem/lldir_utils_objc.h2
-rw-r--r--indra/llfilesystem/lldir_utils_objc.mm2
-rw-r--r--indra/llfilesystem/lldir_win32.cpp13
-rw-r--r--indra/llfilesystem/lldir_win32.h2
-rw-r--r--indra/llfilesystem/lldiskcache.cpp174
-rw-r--r--indra/llfilesystem/lldiskcache.h33
-rw-r--r--indra/llfilesystem/llfilesystem.cpp175
-rw-r--r--indra/llfilesystem/llfilesystem.h29
-rw-r--r--indra/llfilesystem/lllfsthread.cpp2
-rw-r--r--indra/llfilesystem/lllfsthread.h4
-rw-r--r--indra/llfilesystem/tests/lldir_test.cpp31
16 files changed, 204 insertions, 299 deletions
diff --git a/indra/llfilesystem/lldir.cpp b/indra/llfilesystem/lldir.cpp
index cbf4c1ffb8..2818aaf86c 100644
--- a/indra/llfilesystem/lldir.cpp
+++ b/indra/llfilesystem/lldir.cpp
@@ -201,15 +201,15 @@ U32 LLDir::deleteDirAndContents(const std::string& dir_name)
boost::filesystem::path dir_path(dir_name);
#endif
- if (boost::filesystem::exists (dir_path))
+ if (boost::filesystem::exists(dir_path))
{
- if (!boost::filesystem::is_empty (dir_path))
+ if (!boost::filesystem::is_empty(dir_path))
{ // Directory has content
- num_deleted = boost::filesystem::remove_all (dir_path);
+ num_deleted = (U32)boost::filesystem::remove_all(dir_path);
}
else
{ // Directory is empty
- boost::filesystem::remove (dir_path);
+ boost::filesystem::remove(dir_path);
}
}
}
@@ -468,6 +468,7 @@ static std::string ELLPathToString(ELLPath location)
ENT(LL_PATH_DEFAULT_SKIN)
ENT(LL_PATH_FONTS)
ENT(LL_PATH_LAST)
+ ENT(LL_PATH_SCRIPTS)
;
#undef ENT
@@ -588,6 +589,10 @@ std::string LLDir::getExpandedFilename(ELLPath location, const std::string& subd
prefix = add(getAppRODataDir(), "fonts");
break;
+ case LL_PATH_SCRIPTS:
+ prefix = add(getAppRODataDir(), "scripts");
+ break;
+
default:
llassert(0);
}
@@ -638,7 +643,7 @@ std::string LLDir::getBaseFileName(const std::string& filepath, bool strip_exten
std::string LLDir::getDirName(const std::string& filepath) const
{
std::size_t offset = filepath.find_last_of(getDirDelimiter());
- S32 len = (offset == std::string::npos) ? 0 : offset;
+ auto len = (offset == std::string::npos) ? 0 : offset;
std::string dirname = filepath.substr(0, len);
return dirname;
}
@@ -721,6 +726,8 @@ std::vector<std::string> LLDir::findSkinnedFilenames(const std::string& subdir,
const std::string& filename,
ESkinConstraint constraint) const
{
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_UI;
+
// Recognize subdirs that have no localization.
static const std::set<std::string> sUnlocalized = list_of
("") // top-level directory not localized
@@ -876,15 +883,15 @@ std::string LLDir::getTempFilename() const
}
// static
-std::string LLDir::getScrubbedFileName(const std::string uncleanFileName)
+std::string LLDir::getScrubbedFileName(std::string_view uncleanFileName)
{
std::string name(uncleanFileName);
const std::string illegalChars(getForbiddenFileChars());
// replace any illegal file chars with and underscore '_'
- for( unsigned int i = 0; i < illegalChars.length(); i++ )
+ for (const char& ch : illegalChars)
{
- int j = -1;
- while((j = name.find(illegalChars[i])) > -1)
+ std::string::size_type j{ 0 };
+ while ((j = name.find(ch, j)) != std::string::npos)
{
name[j] = '_';
}
diff --git a/indra/llfilesystem/lldir.h b/indra/llfilesystem/lldir.h
index be82f55e46..241f151d47 100644
--- a/indra/llfilesystem/lldir.h
+++ b/indra/llfilesystem/lldir.h
@@ -49,6 +49,7 @@ typedef enum ELLPath
LL_PATH_DEFAULT_SKIN = 17,
LL_PATH_FONTS = 18,
LL_PATH_DUMP = 19,
+ LL_PATH_SCRIPTS = 20,
LL_PATH_LAST
} ELLPath;
@@ -178,7 +179,7 @@ class LLDir
static std::string getDumpLogsDirPath(const std::string &file_name = "");
// For producing safe download file names from potentially unsafe ones
- static std::string getScrubbedFileName(const std::string uncleanFileName);
+ static std::string getScrubbedFileName(std::string_view uncleanFileName);
static std::string getForbiddenFileChars();
void setDumpDir( const std::string& path );
diff --git a/indra/llfilesystem/lldir_linux.cpp b/indra/llfilesystem/lldir_linux.cpp
index cc951ec4b9..b13b42c954 100644
--- a/indra/llfilesystem/lldir_linux.cpp
+++ b/indra/llfilesystem/lldir_linux.cpp
@@ -247,11 +247,11 @@ bool LLDir_Linux::fileExists(const std::string &filename) const
int res = stat(filename.c_str(), &stat_data);
if (!res)
{
- return TRUE;
+ return true;
}
else
{
- return FALSE;
+ return false;
}
}
diff --git a/indra/llfilesystem/lldir_mac.cpp b/indra/llfilesystem/lldir_mac.cpp
index b9560c8234..b9be75c528 100644
--- a/indra/llfilesystem/lldir_mac.cpp
+++ b/indra/llfilesystem/lldir_mac.cpp
@@ -1,6 +1,6 @@
/**
* @file lldir_mac.cpp
- * @brief Implementation of directory utilities for Mac OS X
+ * @brief Implementation of directory utilities for macOS
*
* $LicenseInfo:firstyear=2002&license=viewerlgpl$
* Second Life Viewer Source Code
diff --git a/indra/llfilesystem/lldir_mac.h b/indra/llfilesystem/lldir_mac.h
index dbb8d85e81..f812ee810b 100644
--- a/indra/llfilesystem/lldir_mac.h
+++ b/indra/llfilesystem/lldir_mac.h
@@ -1,6 +1,6 @@
/**
* @file lldir_mac.h
- * @brief Definition of directory utilities class for Mac OS X
+ * @brief Definition of directory utilities class for macOS
*
* $LicenseInfo:firstyear=2000&license=viewerlgpl$
* Second Life Viewer Source Code
diff --git a/indra/llfilesystem/lldir_utils_objc.h b/indra/llfilesystem/lldir_utils_objc.h
index 142933972a..1d9cb34e19 100644
--- a/indra/llfilesystem/lldir_utils_objc.h
+++ b/indra/llfilesystem/lldir_utils_objc.h
@@ -1,6 +1,6 @@
/**
* @file lldir_utils_objc.h
- * @brief Definition of directory utilities class for Mac OS X
+ * @brief Definition of directory utilities class for macOS
*
* $LicenseInfo:firstyear=2020&license=viewerlgpl$
* Second Life Viewer Source Code
diff --git a/indra/llfilesystem/lldir_utils_objc.mm b/indra/llfilesystem/lldir_utils_objc.mm
index 20540fb93c..01fe9e1f2c 100644
--- a/indra/llfilesystem/lldir_utils_objc.mm
+++ b/indra/llfilesystem/lldir_utils_objc.mm
@@ -1,6 +1,6 @@
/**
* @file lldir_utils_objc.mm
- * @brief Cocoa implementation of directory utilities for Mac OS X
+ * @brief Cocoa implementation of directory utilities for macOS
*
* $LicenseInfo:firstyear=2020&license=viewerlgpl$
* Second Life Viewer Source Code
diff --git a/indra/llfilesystem/lldir_win32.cpp b/indra/llfilesystem/lldir_win32.cpp
index 5c85f0d3d4..a607c70b44 100644
--- a/indra/llfilesystem/lldir_win32.cpp
+++ b/indra/llfilesystem/lldir_win32.cpp
@@ -47,14 +47,16 @@ DWORD GetDllVersion(LPCTSTR lpszDllName);
namespace
{ // anonymous
- enum class prst { INIT, OPEN, SKIP } state = prst::INIT;
+ enum class prst { INIT, OPEN, SKIP };
+ prst state{ prst::INIT };
+
// This is called so early that we can't count on static objects being
// properly constructed yet, so declare a pointer instead of an instance.
std::ofstream* prelogf = nullptr;
void prelog(const std::string& message)
{
- boost::optional<std::string> prelog_name;
+ std::optional<std::string> prelog_name;
switch (state)
{
@@ -75,6 +77,7 @@ namespace
(*prelogf) << "========================================================================"
<< std::endl;
// fall through, don't break
+ [[fallthrough]];
case prst::OPEN:
(*prelogf) << message << std::endl;
@@ -230,7 +233,7 @@ LLDir_Win32::LLDir_Win32()
{
w_str[size] = '\0';
mExecutablePathAndName = utf16str_to_utf8str(llutf16string(w_str));
- S32 path_end = mExecutablePathAndName.find_last_of('\\');
+ auto path_end = mExecutablePathAndName.find_last_of('\\');
if (path_end != std::string::npos)
{
mExecutableDir = mExecutablePathAndName.substr(0, path_end);
@@ -379,11 +382,11 @@ bool LLDir_Win32::fileExists(const std::string &filename) const
int res = LLFile::stat(filename, &stat_data);
if (!res)
{
- return TRUE;
+ return true;
}
else
{
- return FALSE;
+ return false;
}
}
diff --git a/indra/llfilesystem/lldir_win32.h b/indra/llfilesystem/lldir_win32.h
index 2830364f15..ab2726f1a0 100644
--- a/indra/llfilesystem/lldir_win32.h
+++ b/indra/llfilesystem/lldir_win32.h
@@ -50,7 +50,7 @@ public:
/*virtual*/ std::string getLLPluginFilename(std::string base_name);
private:
- void* mDirSearch_h;
+ void* mDirSearch_h{ nullptr };
llutf16string mCurrentDir;
};
diff --git a/indra/llfilesystem/lldiskcache.cpp b/indra/llfilesystem/lldiskcache.cpp
index 54e49ebcb8..49904911a9 100644
--- a/indra/llfilesystem/lldiskcache.cpp
+++ b/indra/llfilesystem/lldiskcache.cpp
@@ -39,15 +39,25 @@
#include "lldiskcache.h"
-LLDiskCache::LLDiskCache(const std::string cache_dir,
+ /**
+ * The prefix inserted at the start of a cache file filename to
+ * help identify it as a cache file. It's probably not required
+ * (just the presence in the cache folder is enough) but I am
+ * paranoid about the cache folder being set to something bad
+ * like the users' OS system dir by mistake or maliciously and
+ * this will help to offset any damage if that happens.
+ */
+static const std::string CACHE_FILENAME_PREFIX("sl_cache");
+
+std::string LLDiskCache::sCacheDir;
+
+LLDiskCache::LLDiskCache(const std::string& cache_dir,
const uintmax_t max_size_bytes,
const bool enable_cache_debug_info) :
- mCacheDir(cache_dir),
mMaxSizeBytes(max_size_bytes),
mEnableCacheDebugInfo(enable_cache_debug_info)
{
- mCacheFilenamePrefix = "sl_cache";
-
+ sCacheDir = cache_dir;
LLFile::mkdir(cache_dir);
}
@@ -83,7 +93,7 @@ void LLDiskCache::purge()
{
if (mEnableCacheDebugInfo)
{
- LL_INFOS() << "Total dir size before purge is " << dirFileSize(mCacheDir) << LL_ENDL;
+ LL_INFOS() << "Total dir size before purge is " << dirFileSize(sCacheDir) << LL_ENDL;
}
boost::system::error_code ec;
@@ -93,9 +103,9 @@ void LLDiskCache::purge()
std::vector<file_info_t> file_info;
#if LL_WINDOWS
- std::wstring cache_path(utf8str_to_utf16str(mCacheDir));
+ std::wstring cache_path(utf8str_to_utf16str(sCacheDir));
#else
- std::string cache_path(mCacheDir);
+ std::string cache_path(sCacheDir);
#endif
if (boost::filesystem::is_directory(cache_path, ec) && !ec.failed())
{
@@ -104,7 +114,7 @@ void LLDiskCache::purge()
{
if (boost::filesystem::is_regular_file(*iter, ec) && !ec.failed())
{
- if ((*iter).path().string().find(mCacheFilenamePrefix) != std::string::npos)
+ if ((*iter).path().string().find(CACHE_FILENAME_PREFIX) != std::string::npos)
{
uintmax_t file_size = boost::filesystem::file_size(*iter, ec);
if (ec.failed())
@@ -181,150 +191,22 @@ void LLDiskCache::purge()
LL_INFOS() << line.str() << LL_ENDL;
}
- LL_INFOS() << "Total dir size after purge is " << dirFileSize(mCacheDir) << LL_ENDL;
+ LL_INFOS() << "Total dir size after purge is " << dirFileSize(sCacheDir) << LL_ENDL;
LL_INFOS() << "Cache purge took " << execute_time << " ms to execute for " << file_info.size() << " files" << LL_ENDL;
}
}
-const std::string LLDiskCache::assetTypeToString(LLAssetType::EType at)
-{
- /**
- * Make use of the handy C++17 feature that allows
- * for inline initialization of an std::map<>
- */
- typedef std::map<LLAssetType::EType, std::string> asset_type_to_name_t;
- asset_type_to_name_t asset_type_to_name =
- {
- { LLAssetType::AT_TEXTURE, "TEXTURE" },
- { LLAssetType::AT_SOUND, "SOUND" },
- { LLAssetType::AT_CALLINGCARD, "CALLINGCARD" },
- { LLAssetType::AT_LANDMARK, "LANDMARK" },
- { LLAssetType::AT_SCRIPT, "SCRIPT" },
- { LLAssetType::AT_CLOTHING, "CLOTHING" },
- { LLAssetType::AT_OBJECT, "OBJECT" },
- { LLAssetType::AT_NOTECARD, "NOTECARD" },
- { LLAssetType::AT_CATEGORY, "CATEGORY" },
- { LLAssetType::AT_LSL_TEXT, "LSL_TEXT" },
- { LLAssetType::AT_LSL_BYTECODE, "LSL_BYTECODE" },
- { LLAssetType::AT_TEXTURE_TGA, "TEXTURE_TGA" },
- { LLAssetType::AT_BODYPART, "BODYPART" },
- { LLAssetType::AT_SOUND_WAV, "SOUND_WAV" },
- { LLAssetType::AT_IMAGE_TGA, "IMAGE_TGA" },
- { LLAssetType::AT_IMAGE_JPEG, "IMAGE_JPEG" },
- { LLAssetType::AT_ANIMATION, "ANIMATION" },
- { LLAssetType::AT_GESTURE, "GESTURE" },
- { LLAssetType::AT_SIMSTATE, "SIMSTATE" },
- { LLAssetType::AT_LINK, "LINK" },
- { LLAssetType::AT_LINK_FOLDER, "LINK_FOLDER" },
- { LLAssetType::AT_MARKETPLACE_FOLDER, "MARKETPLACE_FOLDER" },
- { LLAssetType::AT_WIDGET, "WIDGET" },
- { LLAssetType::AT_PERSON, "PERSON" },
- { LLAssetType::AT_MESH, "MESH" },
- { LLAssetType::AT_SETTINGS, "SETTINGS" },
- { LLAssetType::AT_MATERIAL, "MATERIAL" },
- { LLAssetType::AT_UNKNOWN, "UNKNOWN" }
- };
-
- asset_type_to_name_t::iterator iter = asset_type_to_name.find(at);
- if (iter != asset_type_to_name.end())
- {
- return iter->second;
- }
-
- return std::string("UNKNOWN");
-}
-
-const std::string LLDiskCache::metaDataToFilepath(const std::string id,
- LLAssetType::EType at,
- const std::string extra_info)
+const std::string LLDiskCache::metaDataToFilepath(const LLUUID& id, LLAssetType::EType at)
{
- std::ostringstream file_path;
-
- file_path << mCacheDir;
- file_path << gDirUtilp->getDirDelimiter();
- file_path << mCacheFilenamePrefix;
- file_path << "_";
- file_path << id;
- file_path << "_";
- file_path << (extra_info.empty() ? "0" : extra_info);
- //file_path << "_";
- //file_path << assetTypeToString(at); // see SL-14210 Prune descriptive tag from new cache filenames
- // for details of why it was removed. Note that if you put it
- // back or change the format of the filename, the cache files
- // files will be invalidated (and perhaps, more importantly,
- // never deleted unless you delete them manually).
- file_path << ".asset";
-
- return file_path.str();
-}
-
-void LLDiskCache::updateFileAccessTime(const std::string file_path)
-{
- /**
- * Threshold in time_t units that is used to decide if the last access time
- * time of the file is updated or not. Added as a precaution for the concern
- * outlined in SL-14582 about frequent writes on older SSDs reducing their
- * lifespan. I think this is the right place for the threshold value - rather
- * than it being a pref - do comment on that Jira if you disagree...
- *
- * Let's start with 1 hour in time_t units and see how that unfolds
- */
- const std::time_t time_threshold = 1 * 60 * 60;
-
- // current time
- const std::time_t cur_time = std::time(nullptr);
-
- boost::system::error_code ec;
-#if LL_WINDOWS
- // file last write time
- const std::time_t last_write_time = boost::filesystem::last_write_time(utf8str_to_utf16str(file_path), ec);
- if (ec.failed())
- {
- LL_WARNS() << "Failed to read last write time for cache file " << file_path << ": " << ec.message() << LL_ENDL;
- return;
- }
-
- // delta between cur time and last time the file was written
- const std::time_t delta_time = cur_time - last_write_time;
-
- // we only write the new value if the time in time_threshold has elapsed
- // before the last one
- if (delta_time > time_threshold)
- {
- boost::filesystem::last_write_time(utf8str_to_utf16str(file_path), cur_time, ec);
- }
-#else
- // file last write time
- const std::time_t last_write_time = boost::filesystem::last_write_time(file_path, ec);
- if (ec.failed())
- {
- LL_WARNS() << "Failed to read last write time for cache file " << file_path << ": " << ec.message() << LL_ENDL;
- return;
- }
-
- // delta between cur time and last time the file was written
- const std::time_t delta_time = cur_time - last_write_time;
-
- // we only write the new value if the time in time_threshold has elapsed
- // before the last one
- if (delta_time > time_threshold)
- {
- boost::filesystem::last_write_time(file_path, cur_time, ec);
- }
-#endif
-
- if (ec.failed())
- {
- LL_WARNS() << "Failed to update last write time for cache file " << file_path << ": " << ec.message() << LL_ENDL;
- }
+ return llformat("%s%s%s_%s_0.asset", sCacheDir.c_str(), gDirUtilp->getDirDelimiter().c_str(), CACHE_FILENAME_PREFIX.c_str(), id.asString().c_str());
}
const std::string LLDiskCache::getCacheInfo()
{
std::ostringstream cache_info;
- F32 max_in_mb = (F32)mMaxSizeBytes / (1024.0 * 1024.0);
- F32 percent_used = ((F32)dirFileSize(mCacheDir) / (F32)mMaxSizeBytes) * 100.0;
+ F32 max_in_mb = (F32)mMaxSizeBytes / (1024.0f * 1024.0f);
+ F32 percent_used = ((F32)dirFileSize(sCacheDir) / (F32)mMaxSizeBytes) * 100.0f;
cache_info << std::fixed;
cache_info << std::setprecision(1);
@@ -344,9 +226,9 @@ void LLDiskCache::clearCache()
*/
boost::system::error_code ec;
#if LL_WINDOWS
- std::wstring cache_path(utf8str_to_utf16str(mCacheDir));
+ std::wstring cache_path(utf8str_to_utf16str(sCacheDir));
#else
- std::string cache_path(mCacheDir);
+ std::string cache_path(sCacheDir);
#endif
if (boost::filesystem::is_directory(cache_path, ec) && !ec.failed())
{
@@ -355,7 +237,7 @@ void LLDiskCache::clearCache()
{
if (boost::filesystem::is_regular_file(*iter, ec) && !ec.failed())
{
- if ((*iter).path().string().find(mCacheFilenamePrefix) != std::string::npos)
+ if ((*iter).path().string().find(CACHE_FILENAME_PREFIX) != std::string::npos)
{
boost::filesystem::remove(*iter, ec);
if (ec.failed())
@@ -403,7 +285,7 @@ void LLDiskCache::removeOldVFSFiles()
}
}
-uintmax_t LLDiskCache::dirFileSize(const std::string dir)
+uintmax_t LLDiskCache::dirFileSize(const std::string& dir)
{
uintmax_t total_file_size = 0;
@@ -429,7 +311,7 @@ uintmax_t LLDiskCache::dirFileSize(const std::string dir)
{
if (boost::filesystem::is_regular_file(*iter, ec) && !ec.failed())
{
- if ((*iter).path().string().find(mCacheFilenamePrefix) != std::string::npos)
+ if ((*iter).path().string().find(CACHE_FILENAME_PREFIX) != std::string::npos)
{
uintmax_t file_size = boost::filesystem::file_size(*iter, ec);
if (!ec.failed())
diff --git a/indra/llfilesystem/lldiskcache.h b/indra/llfilesystem/lldiskcache.h
index b60e74f8c9..f07b26c2d7 100644
--- a/indra/llfilesystem/lldiskcache.h
+++ b/indra/llfilesystem/lldiskcache.h
@@ -81,7 +81,7 @@ class LLDiskCache :
* a child of the main Viewer cache directory. Defined
* by the setting at 'DiskCacheDirName'
*/
- const std::string cache_dir,
+ const std::string& cache_dir,
/**
* The maximum size of the cache in bytes - Based on the
* setting at 'CacheSize' and 'DiskCachePercentOfTotal'
@@ -104,16 +104,7 @@ class LLDiskCache :
* so many things had to be pushed back there to accomodate it, that I
* decided to move it here. Still not sure that's completely right.
*/
- const std::string metaDataToFilepath(const std::string id,
- LLAssetType::EType at,
- const std::string extra_info);
-
- /**
- * Update the "last write time" of a file to "now". This must be called whenever a
- * file in the cache is read (not written) so that the last time the file was
- * accessed is up to date (This is used in the mechanism for purging the cache)
- */
- void updateFileAccessTime(const std::string file_path);
+ static const std::string metaDataToFilepath(const LLUUID& id, LLAssetType::EType at);
/**
* Purge the oldest items in the cache so that the combined size of all files
@@ -148,13 +139,7 @@ class LLDiskCache :
* directory. Primarily used here to determine the directory size
* before and after the cache purge
*/
- uintmax_t dirFileSize(const std::string dir);
-
- /**
- * Utility function to convert an LLAssetType enum into a
- * string that we use as part of the cache file filename
- */
- const std::string assetTypeToString(LLAssetType::EType at);
+ uintmax_t dirFileSize(const std::string& dir);
private:
/**
@@ -170,17 +155,7 @@ class LLDiskCache :
* setting could potentially point it at a non-cache directory (for example,
* the Windows System dir) with disastrous results.
*/
- std::string mCacheDir;
-
- /**
- * The prefix inserted at the start of a cache file filename to
- * help identify it as a cache file. It's probably not required
- * (just the presence in the cache folder is enough) but I am
- * paranoid about the cache folder being set to something bad
- * like the users' OS system dir by mistake or maliciously and
- * this will help to offset any damage if that happens.
- */
- std::string mCacheFilenamePrefix;
+ static std::string sCacheDir;
/**
* When enabled, displays additional debugging information in
diff --git a/indra/llfilesystem/llfilesystem.cpp b/indra/llfilesystem/llfilesystem.cpp
index 4c836c8838..c8ce9531c2 100644
--- a/indra/llfilesystem/llfilesystem.cpp
+++ b/indra/llfilesystem/llfilesystem.cpp
@@ -34,10 +34,12 @@
#include "llfasttimer.h"
#include "lldiskcache.h"
-const S32 LLFileSystem::READ = 0x00000001;
-const S32 LLFileSystem::WRITE = 0x00000002;
-const S32 LLFileSystem::READ_WRITE = 0x00000003; // LLFileSystem::READ & LLFileSystem::WRITE
-const S32 LLFileSystem::APPEND = 0x00000006; // 0x00000004 & LLFileSystem::WRITE
+#include "boost/filesystem.hpp"
+
+constexpr S32 LLFileSystem::READ = 0x00000001;
+constexpr S32 LLFileSystem::WRITE = 0x00000002;
+constexpr S32 LLFileSystem::READ_WRITE = 0x00000003; // LLFileSystem::READ & LLFileSystem::WRITE
+constexpr S32 LLFileSystem::APPEND = 0x00000006; // 0x00000004 & LLFileSystem::WRITE
static LLTrace::BlockTimerStatHandle FTM_VFILE_WAIT("VFile Wait");
@@ -55,10 +57,7 @@ LLFileSystem::LLFileSystem(const LLUUID& file_id, const LLAssetType::EType file_
if (mode == LLFileSystem::READ)
{
// build the filename (TODO: we do this in a few places - perhaps we should factor into a single function)
- std::string id;
- mFileID.toString(id);
- const std::string extra_info = "";
- const std::string filename = LLDiskCache::getInstance()->metaDataToFilepath(id, mFileType, extra_info);
+ const std::string filename = LLDiskCache::metaDataToFilepath(mFileID, mFileType);
// update the last access time for the file if it exists - this is required
// even though we are reading and not writing because this is the
@@ -67,22 +66,16 @@ LLFileSystem::LLFileSystem(const LLUUID& file_id, const LLAssetType::EType file_
bool exists = gDirUtilp->fileExists(filename);
if (exists)
{
- LLDiskCache::getInstance()->updateFileAccessTime(filename);
+ updateFileAccessTime(filename);
}
}
}
-LLFileSystem::~LLFileSystem()
-{
-}
-
// static
bool LLFileSystem::getExists(const LLUUID& file_id, const LLAssetType::EType file_type)
{
- std::string id_str;
- file_id.toString(id_str);
- const std::string extra_info = "";
- const std::string filename = LLDiskCache::getInstance()->metaDataToFilepath(id_str, file_type, extra_info);
+ LL_PROFILE_ZONE_SCOPED;
+ const std::string filename = LLDiskCache::metaDataToFilepath(file_id, file_type);
llifstream file(filename, std::ios::binary);
if (file.is_open())
@@ -96,10 +89,7 @@ bool LLFileSystem::getExists(const LLUUID& file_id, const LLAssetType::EType fil
// static
bool LLFileSystem::removeFile(const LLUUID& file_id, const LLAssetType::EType file_type, int suppress_error /*= 0*/)
{
- std::string id_str;
- file_id.toString(id_str);
- const std::string extra_info = "";
- const std::string filename = LLDiskCache::getInstance()->metaDataToFilepath(id_str, file_type, extra_info);
+ const std::string filename = LLDiskCache::metaDataToFilepath(file_id, file_type);
LLFile::remove(filename.c_str(), suppress_error);
@@ -110,57 +100,45 @@ bool LLFileSystem::removeFile(const LLUUID& file_id, const LLAssetType::EType fi
bool LLFileSystem::renameFile(const LLUUID& old_file_id, const LLAssetType::EType old_file_type,
const LLUUID& new_file_id, const LLAssetType::EType new_file_type)
{
- std::string old_id_str;
- old_file_id.toString(old_id_str);
- const std::string extra_info = "";
- const std::string old_filename = LLDiskCache::getInstance()->metaDataToFilepath(old_id_str, old_file_type, extra_info);
-
- std::string new_id_str;
- new_file_id.toString(new_id_str);
- const std::string new_filename = LLDiskCache::getInstance()->metaDataToFilepath(new_id_str, new_file_type, extra_info);
+ const std::string old_filename = LLDiskCache::metaDataToFilepath(old_file_id, old_file_type);
+ const std::string new_filename = LLDiskCache::metaDataToFilepath(new_file_id, new_file_type);
// Rename needs the new file to not exist.
LLFileSystem::removeFile(new_file_id, new_file_type, ENOENT);
if (LLFile::rename(old_filename, new_filename) != 0)
{
- // We would like to return FALSE here indicating the operation
+ // We would like to return false here indicating the operation
// failed but the original code does not and doing so seems to
// break a lot of things so we go with the flow...
- //return FALSE;
- LL_WARNS() << "Failed to rename " << old_file_id << " to " << new_id_str << " reason: " << strerror(errno) << LL_ENDL;
+ //return false;
+ LL_WARNS() << "Failed to rename " << old_file_id << " to " << new_file_id << " reason: " << strerror(errno) << LL_ENDL;
}
- return TRUE;
+ return true;
}
// static
S32 LLFileSystem::getFileSize(const LLUUID& file_id, const LLAssetType::EType file_type)
{
- std::string id_str;
- file_id.toString(id_str);
- const std::string extra_info = "";
- const std::string filename = LLDiskCache::getInstance()->metaDataToFilepath(id_str, file_type, extra_info);
+ const std::string filename = LLDiskCache::metaDataToFilepath(file_id, file_type);
S32 file_size = 0;
llifstream file(filename, std::ios::binary);
if (file.is_open())
{
file.seekg(0, std::ios::end);
- file_size = file.tellg();
+ file_size = (S32)file.tellg();
}
return file_size;
}
-BOOL LLFileSystem::read(U8* buffer, S32 bytes)
+bool LLFileSystem::read(U8* buffer, S32 bytes)
{
- BOOL success = FALSE;
+ bool success = false;
- std::string id;
- mFileID.toString(id);
- const std::string extra_info = "";
- const std::string filename = LLDiskCache::getInstance()->metaDataToFilepath(id, mFileType, extra_info);
+ const std::string filename = LLDiskCache::metaDataToFilepath(mFileID, mFileType);
llifstream file(filename, std::ios::binary);
if (file.is_open())
@@ -175,7 +153,7 @@ BOOL LLFileSystem::read(U8* buffer, S32 bytes)
}
else
{
- mBytesRead = file.gcount();
+ mBytesRead = (S32)file.gcount();
}
file.close();
@@ -183,31 +161,28 @@ BOOL LLFileSystem::read(U8* buffer, S32 bytes)
mPosition += mBytesRead;
if (mBytesRead)
{
- success = TRUE;
+ success = true;
}
}
return success;
}
-S32 LLFileSystem::getLastBytesRead()
+S32 LLFileSystem::getLastBytesRead() const
{
return mBytesRead;
}
-BOOL LLFileSystem::eof()
+bool LLFileSystem::eof() const
{
return mPosition >= getSize();
}
-BOOL LLFileSystem::write(const U8* buffer, S32 bytes)
+bool LLFileSystem::write(const U8* buffer, S32 bytes)
{
- std::string id_str;
- mFileID.toString(id_str);
- const std::string extra_info = "";
- const std::string filename = LLDiskCache::getInstance()->metaDataToFilepath(id_str, mFileType, extra_info);
+ const std::string filename = LLDiskCache::metaDataToFilepath(mFileID, mFileType);
- BOOL success = FALSE;
+ bool success = false;
if (mMode == APPEND)
{
@@ -216,12 +191,11 @@ BOOL LLFileSystem::write(const U8* buffer, S32 bytes)
{
ofs.write((const char*)buffer, bytes);
- mPosition = ofs.tellp(); // <FS:Ansariel> Fix asset caching
+ mPosition = (S32)ofs.tellp();
- success = TRUE;
+ success = true;
}
}
- // <FS:Ansariel> Fix asset caching
else if (mMode == READ_WRITE)
{
// Don't truncate if file already exists
@@ -231,7 +205,7 @@ BOOL LLFileSystem::write(const U8* buffer, S32 bytes)
ofs.seekp(mPosition, std::ios::beg);
ofs.write((const char*)buffer, bytes);
mPosition += bytes;
- success = TRUE;
+ success = true;
}
else
{
@@ -241,11 +215,10 @@ BOOL LLFileSystem::write(const U8* buffer, S32 bytes)
{
ofs.write((const char*)buffer, bytes);
mPosition += bytes;
- success = TRUE;
+ success = true;
}
}
}
- // </FS:Ansariel>
else
{
llofstream ofs(filename, std::ios::binary);
@@ -255,14 +228,14 @@ BOOL LLFileSystem::write(const U8* buffer, S32 bytes)
mPosition += bytes;
- success = TRUE;
+ success = true;
}
}
return success;
}
-BOOL LLFileSystem::seek(S32 offset, S32 origin)
+bool LLFileSystem::seek(S32 offset, S32 origin)
{
if (-1 == origin)
{
@@ -278,18 +251,18 @@ BOOL LLFileSystem::seek(S32 offset, S32 origin)
LL_WARNS() << "Attempt to seek past end of file" << LL_ENDL;
mPosition = size;
- return FALSE;
+ return false;
}
else if (new_pos < 0)
{
LL_WARNS() << "Attempt to seek past beginning of file" << LL_ENDL;
mPosition = 0;
- return FALSE;
+ return false;
}
mPosition = new_pos;
- return TRUE;
+ return true;
}
S32 LLFileSystem::tell() const
@@ -297,30 +270,90 @@ S32 LLFileSystem::tell() const
return mPosition;
}
-S32 LLFileSystem::getSize()
+S32 LLFileSystem::getSize() const
{
return LLFileSystem::getFileSize(mFileID, mFileType);
}
-S32 LLFileSystem::getMaxSize()
+S32 LLFileSystem::getMaxSize() const
{
// offer up a huge size since we don't care what the max is
return INT_MAX;
}
-BOOL LLFileSystem::rename(const LLUUID& new_id, const LLAssetType::EType new_type)
+bool LLFileSystem::rename(const LLUUID& new_id, const LLAssetType::EType new_type)
{
LLFileSystem::renameFile(mFileID, mFileType, new_id, new_type);
mFileID = new_id;
mFileType = new_type;
- return TRUE;
+ return true;
}
-BOOL LLFileSystem::remove()
+bool LLFileSystem::remove() const
{
LLFileSystem::removeFile(mFileID, mFileType);
+ return true;
+}
+
+void LLFileSystem::updateFileAccessTime(const std::string& file_path)
+{
+ /**
+ * Threshold in time_t units that is used to decide if the last access time
+ * time of the file is updated or not. Added as a precaution for the concern
+ * outlined in SL-14582 about frequent writes on older SSDs reducing their
+ * lifespan. I think this is the right place for the threshold value - rather
+ * than it being a pref - do comment on that Jira if you disagree...
+ *
+ * Let's start with 1 hour in time_t units and see how that unfolds
+ */
+ constexpr std::time_t time_threshold = 1 * 60 * 60;
+
+ // current time
+ const std::time_t cur_time = std::time(nullptr);
+
+ boost::system::error_code ec;
+#if LL_WINDOWS
+ // file last write time
+ const std::time_t last_write_time = boost::filesystem::last_write_time(utf8str_to_utf16str(file_path), ec);
+ if (ec.failed())
+ {
+ LL_WARNS() << "Failed to read last write time for cache file " << file_path << ": " << ec.message() << LL_ENDL;
+ return;
+ }
+
+ // delta between cur time and last time the file was written
+ const std::time_t delta_time = cur_time - last_write_time;
+
+ // we only write the new value if the time in time_threshold has elapsed
+ // before the last one
+ if (delta_time > time_threshold)
+ {
+ boost::filesystem::last_write_time(utf8str_to_utf16str(file_path), cur_time, ec);
+ }
+#else
+ // file last write time
+ const std::time_t last_write_time = boost::filesystem::last_write_time(file_path, ec);
+ if (ec.failed())
+ {
+ LL_WARNS() << "Failed to read last write time for cache file " << file_path << ": " << ec.message() << LL_ENDL;
+ return;
+ }
- return TRUE;
+ // delta between cur time and last time the file was written
+ const std::time_t delta_time = cur_time - last_write_time;
+
+ // we only write the new value if the time in time_threshold has elapsed
+ // before the last one
+ if (delta_time > time_threshold)
+ {
+ boost::filesystem::last_write_time(file_path, cur_time, ec);
+ }
+#endif
+
+ if (ec.failed())
+ {
+ LL_WARNS() << "Failed to update last write time for cache file " << file_path << ": " << ec.message() << LL_ENDL;
+ }
}
diff --git a/indra/llfilesystem/llfilesystem.h b/indra/llfilesystem/llfilesystem.h
index d934a408c2..10649b6920 100644
--- a/indra/llfilesystem/llfilesystem.h
+++ b/indra/llfilesystem/llfilesystem.h
@@ -38,20 +38,27 @@ class LLFileSystem
{
public:
LLFileSystem(const LLUUID& file_id, const LLAssetType::EType file_type, S32 mode = LLFileSystem::READ);
- ~LLFileSystem();
+ ~LLFileSystem() = default;
- BOOL read(U8* buffer, S32 bytes);
- S32 getLastBytesRead();
- BOOL eof();
+ bool read(U8* buffer, S32 bytes);
+ S32 getLastBytesRead() const;
+ bool eof() const;
- BOOL write(const U8* buffer, S32 bytes);
- BOOL seek(S32 offset, S32 origin = -1);
+ bool write(const U8* buffer, S32 bytes);
+ bool seek(S32 offset, S32 origin = -1);
S32 tell() const;
- S32 getSize();
- S32 getMaxSize();
- BOOL rename(const LLUUID& new_id, const LLAssetType::EType new_type);
- BOOL remove();
+ S32 getSize() const;
+ S32 getMaxSize() const;
+ bool rename(const LLUUID& new_id, const LLAssetType::EType new_type);
+ bool remove() const;
+
+ /**
+ * Update the "last write time" of a file to "now". This must be called whenever a
+ * file in the cache is read (not written) so that the last time the file was
+ * accessed is up to date (This is used in the mechanism for purging the cache)
+ */
+ void updateFileAccessTime(const std::string& file_path);
static bool getExists(const LLUUID& file_id, const LLAssetType::EType file_type);
static bool removeFile(const LLUUID& file_id, const LLAssetType::EType file_type, int suppress_error = 0);
@@ -71,8 +78,6 @@ class LLFileSystem
S32 mPosition;
S32 mMode;
S32 mBytesRead;
-//private:
-// static const std::string idToFilepath(const std::string id, LLAssetType::EType at);
};
#endif // LL_FILESYSTEM_H
diff --git a/indra/llfilesystem/lllfsthread.cpp b/indra/llfilesystem/lllfsthread.cpp
index 7d135b4472..6a882f64a8 100644
--- a/indra/llfilesystem/lllfsthread.cpp
+++ b/indra/llfilesystem/lllfsthread.cpp
@@ -45,7 +45,7 @@ void LLLFSThread::initClass(bool local_is_threaded)
//static
S32 LLLFSThread::updateClass(U32 ms_elapsed)
{
- return sLocal->update((F32)ms_elapsed);
+ return static_cast<S32>(sLocal->update((F32)ms_elapsed));
}
//static
diff --git a/indra/llfilesystem/lllfsthread.h b/indra/llfilesystem/lllfsthread.h
index 3230c0c2ae..c0ed1931bb 100644
--- a/indra/llfilesystem/lllfsthread.h
+++ b/indra/llfilesystem/lllfsthread.h
@@ -114,7 +114,7 @@ public:
//------------------------------------------------------------------------
public:
- LLLFSThread(bool threaded = TRUE);
+ LLLFSThread(bool threaded = true);
~LLLFSThread();
// Return a Request handle
@@ -126,7 +126,7 @@ public:
Responder* responder);
// static initializers
- static void initClass(bool local_is_threaded = TRUE); // Setup sLocal
+ static void initClass(bool local_is_threaded = true); // Setup sLocal
static S32 updateClass(U32 ms_elapsed);
static void cleanupClass(); // Delete sLocal
diff --git a/indra/llfilesystem/tests/lldir_test.cpp b/indra/llfilesystem/tests/lldir_test.cpp
index 6e191ad096..4fa5769f65 100644
--- a/indra/llfilesystem/tests/lldir_test.cpp
+++ b/indra/llfilesystem/tests/lldir_test.cpp
@@ -27,12 +27,14 @@
#include "linden_common.h"
+#include <filesystem>
#include "llstring.h"
#include "tests/StringVec.h"
#include "../lldir.h"
#include "../lldiriterator.h"
#include "../test/lltut.h"
+#include "../test/namedtempfile.h"
#include "stringize.h"
#include <boost/assign/list_of.hpp>
@@ -425,23 +427,19 @@ namespace tut
return path;
}
- std::string makeTestDir( const std::string& dirbase )
+ std::string makeTestDir( )
{
- int counter;
- std::string uniqueDir;
- bool foundUnused;
- std::string delim = gDirUtilp->getDirDelimiter();
+ auto p = NamedTempFile::temp_path();
+ std::filesystem::create_directories(p.native());
- for (counter=0, foundUnused=false; !foundUnused; counter++ )
- {
- char counterStr[3];
- sprintf(counterStr, "%02d", counter);
- uniqueDir = dirbase + counterStr;
- foundUnused = ! ( LLFile::isdir(uniqueDir) || LLFile::isfile(uniqueDir) );
- }
- ensure("test directory '" + uniqueDir + "' creation failed", !LLFile::mkdir(uniqueDir));
+ std::string ret = p.string();
- return uniqueDir + delim; // HACK - apparently, the trailing delimiter is needed...
+ // There's an implicit assumtion all over this code that the returned path ends with "/" (or "\")
+
+ if(ret.size() >= 1 && ret[ ret.size()-1 ] != std::filesystem::path::preferred_separator )
+ ret += std::filesystem::path::preferred_separator;
+
+ return ret;
}
static const char* DirScanFilename[5] = { "file1.abc", "file2.abc", "file1.xyz", "file2.xyz", "file1.mno" };
@@ -497,8 +495,9 @@ namespace tut
// Create the same 5 file names of the two directories
- std::string dir1 = makeTestDir(dirTemp + "LLDirIterator");
- std::string dir2 = makeTestDir(dirTemp + "LLDirIterator");
+ std::string dir1 = makeTestDir();
+ std::string dir2 = makeTestDir();
+
std::string dir1files[5];
std::string dir2files[5];
for (int i=0; i<5; i++)