From 25dc8660efedecfd9f021142ac1e4ff3639e80d4 Mon Sep 17 00:00:00 2001 From: Rye Date: Tue, 30 Dec 2025 11:39:16 -0500 Subject: Clean up LLFile and LLFilesystem operations to reduce temporaries allocations and utf8->utf16 conversions Fix LLFile::tmpdir failing when temp directory is located in a unicode path on windows Add Tracy profiler tagging to LLFile that's disabled by default Replace LLFile::utf8StringToWstring with our fsyspath std::filesystem::path adapter Introduce std::filesystem::path to llifstream/llofstream wrappers Add move operators to fsyspath to match copy operator Restore LLUniqueFile RAII class for direct c file io wrapping and reducing merge conflicts with downstream code that may depend upon it Signed-off-by: Rye --- indra/newview/llinventorymodel.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'indra/newview/llinventorymodel.cpp') diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index 043fd7003d..9491c9d610 100644 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -2745,7 +2745,7 @@ bool LLInventoryModel::loadSkeleton( const S32 NO_VERSION = LLViewerInventoryCategory::VERSION_UNKNOWN; std::string gzip_filename(inventory_filename); gzip_filename.append(".gz"); - LLFILE* fp = LLFile::fopen(gzip_filename, "rb"); + LLFILE* fp = LLFile::fopen(gzip_filename, TEXT("rb")); bool remove_inventory_file = false; if (LLAppViewer::instance()->isSecondInstance()) { @@ -4908,7 +4908,7 @@ bool decompress_file(const char* src_filename, const char* dst_filename) // open the files src = gzopen(src_filename, "rb"); if(!src) goto err_decompress; - dst = LLFile::fopen(dst_filename, "wb"); + dst = LLFile::fopen(dst_filename, TEXT("wb")); if(!dst) goto err_decompress; // decompress. -- cgit v1.3 From 9873abfb94f0d9cbc6df60fef9df622ef51355ec Mon Sep 17 00:00:00 2001 From: Rye Date: Mon, 5 Jan 2026 15:01:23 -0500 Subject: Address feedback from copilot Signed-off-by: Rye --- indra/llappearance/llpolymesh.cpp | 2 +- indra/llcommon/llcrc.cpp | 2 +- indra/llcommon/llcrc.h | 2 +- indra/llcommon/llfile.h | 10 ++++------ indra/llcommon/llprocessor.cpp | 4 ++-- indra/llcommon/llsys.cpp | 6 +++--- indra/llfilesystem/lldir.cpp | 2 +- indra/llfilesystem/tests/lldir_test.cpp | 2 +- indra/llimage/llimagedimensionsinfo.cpp | 2 +- indra/llimage/llimagetga.cpp | 2 +- indra/llmessage/llassetstorage.cpp | 2 +- indra/llmessage/lltransfersourcefile.cpp | 2 +- indra/llmessage/lltransfertargetfile.cpp | 2 +- indra/llmessage/llxfer_file.cpp | 16 ++++++++-------- indra/llmessage/message.cpp | 4 ++-- indra/llmessage/tests/lldatapacker_test.cpp | 4 ++-- indra/llrender/llshadermgr.cpp | 4 ++-- indra/llui/lluicolortable.cpp | 2 +- indra/llui/llxuiparser.cpp | 4 ++-- indra/llxml/llcontrol.cpp | 2 +- indra/llxml/llxmlparser.cpp | 4 ++-- indra/newview/llconversationlog.cpp | 4 ++-- indra/newview/lldrawpoolbump.cpp | 2 +- indra/newview/llfloateruipreview.cpp | 2 +- indra/newview/llinventorymodel.cpp | 4 ++-- indra/newview/llkeyconflict.cpp | 2 +- indra/newview/lllogchat.cpp | 12 ++++++------ indra/newview/llmutelist.cpp | 8 ++++---- indra/newview/llpreviewnotecard.cpp | 4 ++-- indra/newview/llpreviewscript.cpp | 4 ++-- indra/newview/llstartup.cpp | 6 +++--- indra/newview/lltoolbarview.cpp | 2 +- indra/newview/llviewerassetstorage.cpp | 2 +- indra/newview/llviewerinput.cpp | 2 +- indra/newview/llviewermenufile.cpp | 2 +- indra/newview/llviewerstatsrecorder.cpp | 2 +- 36 files changed, 68 insertions(+), 70 deletions(-) (limited to 'indra/newview/llinventorymodel.cpp') diff --git a/indra/llappearance/llpolymesh.cpp b/indra/llappearance/llpolymesh.cpp index b579dc007b..45f51950ec 100644 --- a/indra/llappearance/llpolymesh.cpp +++ b/indra/llappearance/llpolymesh.cpp @@ -280,7 +280,7 @@ bool LLPolyMeshSharedData::loadMesh( const std::string& fileName ) LL_ERRS() << "Filename is Empty!" << LL_ENDL; return false; } - LLFILE* fp = LLFile::fopen(fileName, TEXT("rb")); /*Flawfinder: ignore*/ + LLFILE* fp = LLFile::fopen(fileName, LLFILE_MODE("rb")); /*Flawfinder: ignore*/ if (!fp) { LLError::LLUserWarningMsg::showMissingFiles(); diff --git a/indra/llcommon/llcrc.cpp b/indra/llcommon/llcrc.cpp index f836a12c35..33bf01a29b 100644 --- a/indra/llcommon/llcrc.cpp +++ b/indra/llcommon/llcrc.cpp @@ -166,7 +166,7 @@ void LLCRC::update(const std::string& filename) return; } - FILE* fp = LLFile::fopen(filename, TEXT("rb")); /* Flawfinder: ignore */ + FILE* fp = LLFile::fopen(filename, LLFILE_MODE("rb")); /* Flawfinder: ignore */ if (fp) { diff --git a/indra/llcommon/llcrc.h b/indra/llcommon/llcrc.h index cbf4cf4e75..2ea5fbc3b0 100644 --- a/indra/llcommon/llcrc.h +++ b/indra/llcommon/llcrc.h @@ -36,7 +36,7 @@ // example (don't try this at work kids): // // LLCRC crc; -// FILE* fp = LLFile::fopen(filename,TEXT("rb")); +// FILE* fp = LLFile::fopen(filename,LLFILE_MODE("rb")); // while(!feof(fp)) { // crc.update(fgetc(fp)); // } diff --git a/indra/llcommon/llfile.h b/indra/llcommon/llfile.h index 7e8e114098..8de3f5c9b4 100755 --- a/indra/llcommon/llfile.h +++ b/indra/llcommon/llfile.h @@ -56,12 +56,10 @@ typedef FILE LLFILE; #include "fsyspath.h" #include "llstring.h" // safe char* -> std::string conversion -#ifndef TEXT #if LL_WINDOWS -#define TEXT(flags) L##flags +#define LLFILE_MODE(flags) L##flags #else -#define TEXT(flags) flags -#endif +#define LLFILE_MODE(flags) flags #endif /// This class provides a selection of functions to operate on files through names and @@ -415,7 +413,7 @@ public: std::error_code ec; return copy(source, target, std::filesystem::copy_options::overwrite_existing, ec); } - inline static bool copy(const std::string& source, char* target) + inline static bool copy(const std::string& source, const char* target) { std::error_code ec; return copy(source, target, std::filesystem::copy_options::overwrite_existing, ec); @@ -686,7 +684,7 @@ private: #else typedef int llfile_handle_t; const llfile_handle_t InvalidHandle = -1; - llfile_handle_t mHandle = -1;; // The file handle/descriptor + llfile_handle_t mHandle = -1; // The file handle/descriptor #endif std::ios_base::openmode mOpen{}; // Used to emulate std::ios_base::app under Windows diff --git a/indra/llcommon/llprocessor.cpp b/indra/llcommon/llprocessor.cpp index 7656986fe2..9d0ef45bee 100644 --- a/indra/llcommon/llprocessor.cpp +++ b/indra/llcommon/llprocessor.cpp @@ -837,7 +837,7 @@ private: void get_proc_cpuinfo() { std::map< std::string, std::string > cpuinfo; - LLFILE* cpuinfo_fp = LLFile::fopen(CPUINFO_FILE, TEXT("rb")); + LLFILE* cpuinfo_fp = LLFile::fopen(CPUINFO_FILE, LLFILE_MODE("rb")); if(cpuinfo_fp) { char line[MAX_STRING]; @@ -954,7 +954,7 @@ private: std::ostringstream s; // *NOTE:Mani - This is for linux only. - LLFILE* cpuinfo = LLFile::fopen(CPUINFO_FILE, TEXT("rb")); + LLFILE* cpuinfo = LLFile::fopen(CPUINFO_FILE, LLFILE_MODE("rb")); if(cpuinfo) { char line[MAX_STRING]; diff --git a/indra/llcommon/llsys.cpp b/indra/llcommon/llsys.cpp index 499de996e2..5ef042b5a7 100644 --- a/indra/llcommon/llsys.cpp +++ b/indra/llcommon/llsys.cpp @@ -514,7 +514,7 @@ namespace { #if LL_LINUX constexpr U32 STATUS_SIZE = 2048; - LLFILE* status_filep = LLFile::fopen("/proc/self/status", TEXT("rb")); + LLFILE* status_filep = LLFile::fopen("/proc/self/status", LLFILE_MODE("rb")); if (status_filep) { char buff[STATUS_SIZE]; /* Flawfinder: ignore */ @@ -1273,7 +1273,7 @@ bool gunzip_file(const std::string& srcfile, const std::string& dstfile) src = gzopen(srcfile.c_str(), "rb"); #endif if (! src) goto err; - dst = LLFile::fopen(tmpfile, TEXT("wb")); /* Flawfinder: ignore */ + dst = LLFile::fopen(tmpfile, LLFILE_MODE("wb")); /* Flawfinder: ignore */ if (! dst) goto err; do { @@ -1314,7 +1314,7 @@ bool gzip_file(const std::string& srcfile, const std::string& dstfile) #endif if (! dst) goto err; - src = LLFile::fopen(srcfile, TEXT("rb")); /* Flawfinder: ignore */ + src = LLFile::fopen(srcfile, LLFILE_MODE("rb")); /* Flawfinder: ignore */ if (! src) goto err; while ((bytes = (S32)fread(buffer, sizeof(U8), COMPRESS_BUFFER_SIZE, src)) > 0) diff --git a/indra/llfilesystem/lldir.cpp b/indra/llfilesystem/lldir.cpp index 3ec8983e8a..1a647362c5 100755 --- a/indra/llfilesystem/lldir.cpp +++ b/indra/llfilesystem/lldir.cpp @@ -1010,7 +1010,7 @@ bool LLDir::setCacheDir(const std::string &path) { LLFile::mkdir(path); std::string tempname = add(path, "temp"); - LLFILE* file = LLFile::fopen(tempname, TEXT("wt")); + LLFILE* file = LLFile::fopen(tempname, LLFILE_MODE("wt")); if (file) { fclose(file); diff --git a/indra/llfilesystem/tests/lldir_test.cpp b/indra/llfilesystem/tests/lldir_test.cpp index b879fef48a..412feb147b 100644 --- a/indra/llfilesystem/tests/lldir_test.cpp +++ b/indra/llfilesystem/tests/lldir_test.cpp @@ -405,7 +405,7 @@ namespace tut std::string makeTestFile( const std::string& dir, const std::string& file ) { std::string path = dir + file; - LLFILE* handle = LLFile::fopen(path, TEXT("w")); + LLFILE* handle = LLFile::fopen(path, LLFILE_MODE("w")); ensure("failed to open test file '"+path+"'", handle != NULL ); // Harbison & Steele, 4th ed., p. 366: "If an error occurs, fputs // returns EOF; otherwise, it returns some other, nonnegative value." diff --git a/indra/llimage/llimagedimensionsinfo.cpp b/indra/llimage/llimagedimensionsinfo.cpp index 1d93014e1b..2ae7760d4c 100644 --- a/indra/llimage/llimagedimensionsinfo.cpp +++ b/indra/llimage/llimagedimensionsinfo.cpp @@ -166,7 +166,7 @@ bool LLImageDimensionsInfo::getImageDimensionsJpeg() { sJpegErrorEncountered = false; clean(); - FILE* fp = LLFile::fopen(mSrcFilename, TEXT("rb")); + FILE* fp = LLFile::fopen(mSrcFilename, LLFILE_MODE("rb")); if (!fp) { setLastError("Unable to open file for reading", mSrcFilename); diff --git a/indra/llimage/llimagetga.cpp b/indra/llimage/llimagetga.cpp index 7c6686db95..7b09553974 100644 --- a/indra/llimage/llimagetga.cpp +++ b/indra/llimage/llimagetga.cpp @@ -1191,7 +1191,7 @@ bool LLImageTGA::loadFile( const std::string& path ) return false; } - LLFILE* file = LLFile::fopen(path, TEXT("rb")); /* Flawfinder: ignore */ + LLFILE* file = LLFile::fopen(path, LLFILE_MODE("rb")); /* Flawfinder: ignore */ if( !file ) { LL_WARNS() << "Couldn't open file " << path << LL_ENDL; diff --git a/indra/llmessage/llassetstorage.cpp b/indra/llmessage/llassetstorage.cpp index 13be0161b4..a8f0554a71 100644 --- a/indra/llmessage/llassetstorage.cpp +++ b/indra/llmessage/llassetstorage.cpp @@ -1402,7 +1402,7 @@ void LLAssetStorage::legacyGetDataCallback(const LLUUID &uuid, uuid.toString(uuid_str); filename = llformat("%s.%s",gDirUtilp->getExpandedFilename(LL_PATH_CACHE,uuid_str).c_str(),LLAssetType::lookup(type)); - LLFILE* fp = LLFile::fopen(filename, TEXT("wb")); /* Flawfinder: ignore */ + LLFILE* fp = LLFile::fopen(filename, LLFILE_MODE("wb")); /* Flawfinder: ignore */ if (fp) { const S32 buf_size = 65536; diff --git a/indra/llmessage/lltransfersourcefile.cpp b/indra/llmessage/lltransfersourcefile.cpp index c2bf5c2afa..d2d264c520 100644 --- a/indra/llmessage/lltransfersourcefile.cpp +++ b/indra/llmessage/lltransfersourcefile.cpp @@ -62,7 +62,7 @@ void LLTransferSourceFile::initTransfer() return; } // Look for the file. - mFP = LLFile::fopen(mParams.getFilename(), TEXT("rb")); /* Flawfinder: ignore */ + mFP = LLFile::fopen(mParams.getFilename(), LLFILE_MODE("rb")); /* Flawfinder: ignore */ if (!mFP) { sendTransferStatus(LLTS_ERROR); diff --git a/indra/llmessage/lltransfertargetfile.cpp b/indra/llmessage/lltransfertargetfile.cpp index cc66befcae..05dba219ed 100644 --- a/indra/llmessage/lltransfertargetfile.cpp +++ b/indra/llmessage/lltransfertargetfile.cpp @@ -75,7 +75,7 @@ LLTSCode LLTransferTargetFile::dataCallback(const S32 packet_id, U8 *in_datap, c if (!mFP) { - mFP = LLFile::fopen(mParams.mFilename, TEXT("wb")); /* Flawfinder: ignore */ + mFP = LLFile::fopen(mParams.mFilename, LLFILE_MODE("wb")); /* Flawfinder: ignore */ if (!mFP) { diff --git a/indra/llmessage/llxfer_file.cpp b/indra/llmessage/llxfer_file.cpp index f0310c6297..5f27cc4827 100644 --- a/indra/llmessage/llxfer_file.cpp +++ b/indra/llmessage/llxfer_file.cpp @@ -161,7 +161,7 @@ S32 LLXfer_File::initializeRequest(U64 xfer_id, S32 LLXfer_File::startDownload() { S32 retval = 0; // presume success - mFp = LLFile::fopen(mTempFilename,TEXT("w+b")); /* Flawfinder : ignore */ + mFp = LLFile::fopen(mTempFilename,LLFILE_MODE("w+b")); /* Flawfinder : ignore */ if (mFp) { fclose(mFp); @@ -209,7 +209,7 @@ S32 LLXfer_File::startSend (U64 xfer_id, const LLHost &remote_host) mBufferStartOffset = 0; // We leave the file open, assuming we'll start reading and sending soon - mFp = LLFile::fopen(mLocalFilename,TEXT("rb")); /* Flawfinder : ignore */ + mFp = LLFile::fopen(mLocalFilename, LLFILE_MODE("rb")); /* Flawfinder : ignore */ if (mFp) { fseek(mFp,0,SEEK_END); @@ -252,7 +252,7 @@ S32 LLXfer_File::reopenFileHandle() if (mFp == NULL) { - mFp = LLFile::fopen(mLocalFilename,TEXT("rb")); /* Flawfinder : ignore */ + mFp = LLFile::fopen(mLocalFilename, LLFILE_MODE("rb")); /* Flawfinder : ignore */ if (mFp == NULL) { LL_INFOS("Xfer") << "Warning: " << mLocalFilename << " not found when re-opening file" << LL_ENDL; @@ -313,7 +313,7 @@ S32 LLXfer_File::flush() { LL_ERRS("Xfer") << "Overwriting open file pointer!" << LL_ENDL; } - mFp = LLFile::fopen(mTempFilename,TEXT("a+b")); /* Flawfinder : ignore */ + mFp = LLFile::fopen(mTempFilename, LLFILE_MODE("a+b")); /* Flawfinder : ignore */ if (mFp) { @@ -381,11 +381,11 @@ S32 LLXfer_File::processEOF() } else { - //LLFILE* fp = LLFile::fopen(mTempFilename, TEXT("r")); + //LLFILE* fp = LLFile::fopen(mTempFilename, LLFILE_MODE("r")); //LL_WARNS() << "File " << mTempFilename << " does " // << (!fp ? "not" : "" ) << " exit." << LL_ENDL; //if(fp) fclose(fp); - //fp = LLFile::fopen(mLocalFilename, TEXT("r")); + //fp = LLFile::fopen(mLocalFilename, LLFILE_MODE("r")); //LL_WARNS() << "File " << mLocalFilename << " does " // << (!fp ? "not" : "" ) << " exit." << LL_ENDL; //if(fp) fclose(fp); @@ -452,8 +452,8 @@ U32 LLXfer_File::getXferTypeTag() S32 copy_file(const std::string& from, const std::string& to) { S32 rv = 0; - LLFILE* in = LLFile::fopen(from, TEXT("rb")); /*Flawfinder: ignore*/ - LLFILE* out = LLFile::fopen(to, TEXT("wb")); /*Flawfinder: ignore*/ + LLFILE* in = LLFile::fopen(from, LLFILE_MODE("rb")); /*Flawfinder: ignore*/ + LLFILE* out = LLFile::fopen(to, LLFILE_MODE("wb")); /*Flawfinder: ignore*/ if(in && out) { S32 read = 0; diff --git a/indra/llmessage/message.cpp b/indra/llmessage/message.cpp index 5b3b57f11e..df58c8a7f3 100644 --- a/indra/llmessage/message.cpp +++ b/indra/llmessage/message.cpp @@ -2376,7 +2376,7 @@ void dump_prehash_files() { U32 i; std::string filename("../../indra/llmessage/message_prehash.h"); - LLFILE* fp = LLFile::fopen(filename, TEXT("w")); /* Flawfinder: ignore */ + LLFILE* fp = LLFile::fopen(filename, LLFILE_MODE("w")); /* Flawfinder: ignore */ if (fp) { fprintf( @@ -2407,7 +2407,7 @@ void dump_prehash_files() fclose(fp); } filename = std::string("../../indra/llmessage/message_prehash.cpp"); - fp = LLFile::fopen(filename, TEXT("w")); /* Flawfinder: ignore */ + fp = LLFile::fopen(filename, LLFILE_MODE("w")); /* Flawfinder: ignore */ if (fp) { fprintf( diff --git a/indra/llmessage/tests/lldatapacker_test.cpp b/indra/llmessage/tests/lldatapacker_test.cpp index 92a2c31ca8..5823980d43 100644 --- a/indra/llmessage/tests/lldatapacker_test.cpp +++ b/indra/llmessage/tests/lldatapacker_test.cpp @@ -348,7 +348,7 @@ namespace tut { F32 f_val = 44.44f, f_unpkval; - LLFILE* fp = LLFile::fopen(TEST_FILE_NAME, TEXT("w+")); + LLFILE* fp = LLFile::fopen(TEST_FILE_NAME, LLFILE_MODE("w+")); if(!fp) { LL_ERRS() << "File couldnt be open" << LL_ENDL; @@ -403,7 +403,7 @@ namespace tut LLVector4 unpkllvec4; LLUUID unpkuuid; - LLFILE* fp = LLFile::fopen(TEST_FILE_NAME,TEXT("w+")); + LLFILE* fp = LLFile::fopen(TEST_FILE_NAME, LLFILE_MODE("w+")); if(!fp) { LL_ERRS() << "File couldnt be open" << LL_ENDL; diff --git a/indra/llrender/llshadermgr.cpp b/indra/llrender/llshadermgr.cpp index 0ed98f2e7e..f6738364a6 100644 --- a/indra/llrender/llshadermgr.cpp +++ b/indra/llrender/llshadermgr.cpp @@ -501,7 +501,7 @@ GLuint LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shader_lev open_file_name = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "shaders/errorF.glsl"); } - file = LLFile::fopen(open_file_name, TEXT("r")); + file = LLFile::fopen(open_file_name, LLFILE_MODE("r")); } else #endif @@ -529,7 +529,7 @@ GLuint LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shader_lev */ LL_DEBUGS("ShaderLoading") << "Looking in " << open_file_name << LL_ENDL; - file = LLFile::fopen(open_file_name, TEXT("r")); /* Flawfinder: ignore */ + file = LLFile::fopen(open_file_name, LLFILE_MODE("r")); /* Flawfinder: ignore */ if (file) { LL_DEBUGS("ShaderLoading") << "Loading file: " << open_file_name << " (Want class " << gpu_class << ")" << LL_ENDL; diff --git a/indra/llui/lluicolortable.cpp b/indra/llui/lluicolortable.cpp index 206d02b366..cd062b23b8 100644 --- a/indra/llui/lluicolortable.cpp +++ b/indra/llui/lluicolortable.cpp @@ -298,7 +298,7 @@ void LLUIColorTable::saveUserSettings() const if(!output_node->isNull()) { const std::string& filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "colors.xml"); - LLFILE *fp = LLFile::fopen(filename, TEXT("w")); + LLFILE *fp = LLFile::fopen(filename, LLFILE_MODE("w")); if(fp != NULL) { diff --git a/indra/llui/llxuiparser.cpp b/indra/llui/llxuiparser.cpp index e3d806bdd0..9bf2f4220c 100644 --- a/indra/llui/llxuiparser.cpp +++ b/indra/llui/llxuiparser.cpp @@ -637,7 +637,7 @@ void LLXUIXSDWriter::writeXSD(const std::string& type_name, const std::string& p } } - LLFILE* xsd_file = LLFile::fopen(file_name.c_str(), TEXT("w")); + LLFILE* xsd_file = LLFile::fopen(file_name.c_str(), LLFILE_MODE("w")); LLXMLNode::writeHeaderToFile(xsd_file); root_nodep->writeToFile(xsd_file); fclose(xsd_file); @@ -1397,7 +1397,7 @@ bool LLSimpleXUIParser::readXUI(const std::string& filename, LLInitParam::BaseBl mCurReadDepth = 0; setParseSilently(silent); - ScopedFile file(filename, TEXT("rb")); + ScopedFile file(filename, LLFILE_MODE("rb")); if( !file.isOpen() ) { LL_WARNS("ReadXUI") << "Unable to open file " << filename << LL_ENDL; diff --git a/indra/llxml/llcontrol.cpp b/indra/llxml/llcontrol.cpp index a8e44f7bdd..24d2facc4c 100644 --- a/indra/llxml/llcontrol.cpp +++ b/indra/llxml/llcontrol.cpp @@ -399,7 +399,7 @@ void LLControlGroup::cleanup() if(mSettingsProfile && getCount.size() != 0) { std::string file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, SETTINGS_PROFILE); - LLFILE* out = LLFile::fopen(file, TEXT("w")); /* Flawfinder: ignore */ + LLFILE* out = LLFile::fopen(file, LLFILE_MODE("w")); /* Flawfinder: ignore */ if(!out) { LL_WARNS("SettingsProfile") << "Error opening " << SETTINGS_PROFILE << LL_ENDL; diff --git a/indra/llxml/llxmlparser.cpp b/indra/llxml/llxmlparser.cpp index 5aac9100dd..8afd412cda 100644 --- a/indra/llxml/llxmlparser.cpp +++ b/indra/llxml/llxmlparser.cpp @@ -72,7 +72,7 @@ bool LLXmlParser::parseFile(const std::string &path) bool success = true; - LLFILE* file = LLFile::fopen(path, TEXT("rb")); /* Flawfinder: ignore */ + LLFILE* file = LLFile::fopen(path, LLFILE_MODE("rb")); /* Flawfinder: ignore */ if( !file ) { mAuxErrorString = llformat( "Couldn't open file %s", path.c_str()); @@ -388,7 +388,7 @@ int main() { char buf[1024]; - LLFILE* file = LLFile::fopen("test.xml", TEXT("rb")); + LLFILE* file = LLFile::fopen("test.xml", LLFILE_MODE("rb")); if( !file ) { return 1; diff --git a/indra/newview/llconversationlog.cpp b/indra/newview/llconversationlog.cpp index 63a3743ef7..bfcc2e4182 100644 --- a/indra/newview/llconversationlog.cpp +++ b/indra/newview/llconversationlog.cpp @@ -512,7 +512,7 @@ bool LLConversationLog::saveToFile(const std::string& filename) return false; } - LLFILE* fp = LLFile::fopen(filename, TEXT("wb")); + LLFILE* fp = LLFile::fopen(filename, LLFILE_MODE("wb")); if (!fp) { LL_WARNS() << "Couldn't open call log list" << filename << LL_ENDL; @@ -556,7 +556,7 @@ bool LLConversationLog::loadFromFile(const std::string& filename) return false; } - LLFILE* fp = LLFile::fopen(filename, TEXT("rb")); + LLFILE* fp = LLFile::fopen(filename, LLFILE_MODE("rb")); if (!fp) { LL_WARNS() << "Couldn't open call log list" << filename << LL_ENDL; diff --git a/indra/newview/lldrawpoolbump.cpp b/indra/newview/lldrawpoolbump.cpp index 200fce7b5b..a42972205a 100644 --- a/indra/newview/lldrawpoolbump.cpp +++ b/indra/newview/lldrawpoolbump.cpp @@ -114,7 +114,7 @@ void LLStandardBumpmap::addstandard() gStandardBumpmapList[LLStandardBumpmap::sStandardBumpmapCount++] = LLStandardBumpmap("Darkness"); // BE_DARKNESS std::string file_name = gDirUtilp->getExpandedFilename( LL_PATH_APP_SETTINGS, "std_bump.ini" ); - LLFILE* file = LLFile::fopen( file_name, TEXT("rt") ); /*Flawfinder: ignore*/ + LLFILE* file = LLFile::fopen( file_name, LLFILE_MODE("rt") ); /*Flawfinder: ignore*/ if( !file ) { LL_WARNS() << "Could not open std_bump <" << file_name << ">" << LL_ENDL; diff --git a/indra/newview/llfloateruipreview.cpp b/indra/newview/llfloateruipreview.cpp index cf710d45dd..637871da0d 100755 --- a/indra/newview/llfloateruipreview.cpp +++ b/indra/newview/llfloateruipreview.cpp @@ -574,7 +574,7 @@ void LLFloaterUIPreview::onClickExportSchema() // std::string file_name(template_path + gDirUtilp->getDirDelimiter() + widget_name + ".rng"); - // LLFILE* rng_file = LLFile::fopen(file_name.c_str(), TEXT("w")); + // LLFILE* rng_file = LLFile::fopen(file_name.c_str(), LLFILE_MODE("w")); // { // LLXMLNode::writeHeaderToFile(rng_file); // const bool use_type_decorations = false; diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index 9491c9d610..c34df48f7d 100644 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -2745,7 +2745,7 @@ bool LLInventoryModel::loadSkeleton( const S32 NO_VERSION = LLViewerInventoryCategory::VERSION_UNKNOWN; std::string gzip_filename(inventory_filename); gzip_filename.append(".gz"); - LLFILE* fp = LLFile::fopen(gzip_filename, TEXT("rb")); + LLFILE* fp = LLFile::fopen(gzip_filename, LLFILE_MODE("rb")); bool remove_inventory_file = false; if (LLAppViewer::instance()->isSecondInstance()) { @@ -4908,7 +4908,7 @@ bool decompress_file(const char* src_filename, const char* dst_filename) // open the files src = gzopen(src_filename, "rb"); if(!src) goto err_decompress; - dst = LLFile::fopen(dst_filename, TEXT("wb")); + dst = LLFile::fopen(dst_filename, LLFILE_MODE("wb")); if(!dst) goto err_decompress; // decompress. diff --git a/indra/newview/llkeyconflict.cpp b/indra/newview/llkeyconflict.cpp index 458d5225e1..c082c632f1 100644 --- a/indra/newview/llkeyconflict.cpp +++ b/indra/newview/llkeyconflict.cpp @@ -575,7 +575,7 @@ void LLKeyConflictHandler::saveToSettings(bool temporary) // Write the resulting XML to file if (!output_node->isNull()) { - LLFILE *fp = LLFile::fopen(filename, TEXT("w")); + LLFILE* fp = LLFile::fopen(filename, LLFILE_MODE("w")); if (fp != NULL) { LLXMLNode::writeHeaderToFile(fp); diff --git a/indra/newview/lllogchat.cpp b/indra/newview/lllogchat.cpp index 405530f5bd..59f6993a0b 100644 --- a/indra/newview/lllogchat.cpp +++ b/indra/newview/lllogchat.cpp @@ -453,7 +453,7 @@ void LLLogChat::loadChatHistory(const std::string& file_name, std::list& m // If we got here, we managed to stat the file. // Open the file to read in binary mode to prevent interpreting other characters as EOF - LLFILE* fptr = LLFile::fopen(log_file_name, TEXT("rb")); /*Flawfinder: ignore*/ + LLFILE* fptr = LLFile::fopen(log_file_name, LLFILE_MODE("rb")); /*Flawfinder: ignore*/ if (!fptr) { // Ok, this is strange but not really tragic in the big picture of things LL_WARNS("ChatHistory") << "Unable to read file " << log_file_name << " after stat was successful" << LL_ENDL; @@ -890,7 +890,7 @@ bool LLLogChat::isAdHocTranscriptExist(std::string file_name) bool LLLogChat::isTranscriptFileFound(std::string fullname) { bool result = false; - LLFILE * filep = LLFile::fopen(fullname, TEXT("rb")); + LLFILE * filep = LLFile::fopen(fullname, LLFILE_MODE("rb")); if (NULL != filep) { if (makeLogFileName("chat") == fullname) @@ -1183,7 +1183,7 @@ void LLLoadHistoryThread::loadHistory(const std::string& file_name, std::listgetExpandedFilename(LL_PATH_PER_SL_ACCOUNT, "render_mute_settings.txt"); - LLFILE* fp = LLFile::fopen(filename, TEXT("wb")); + LLFILE* fp = LLFile::fopen(filename, LLFILE_MODE("wb")); if (!fp) { LL_WARNS() << "Couldn't open render mute list file: " << filename << LL_ENDL; @@ -963,7 +963,7 @@ bool LLRenderMuteList::saveToFile() bool LLRenderMuteList::loadFromFile() { std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, "render_mute_settings.txt"); - LLFILE* fp = LLFile::fopen(filename, TEXT("rb")); + LLFILE* fp = LLFile::fopen(filename, LLFILE_MODE("rb")); if (!fp) { LL_WARNS() << "Couldn't open render mute list file: " << filename << LL_ENDL; diff --git a/indra/newview/llpreviewnotecard.cpp b/indra/newview/llpreviewnotecard.cpp index 6928d7e6c3..cecda23e7b 100644 --- a/indra/newview/llpreviewnotecard.cpp +++ b/indra/newview/llpreviewnotecard.cpp @@ -801,7 +801,7 @@ bool LLPreviewNotecard::loadNotecardText(const std::string& filename) return false; } - LLFILE* file = LLFile::fopen(filename, TEXT("rb")); /*Flawfinder: ignore*/ + LLFILE* file = LLFile::fopen(filename, LLFILE_MODE("rb")); /*Flawfinder: ignore*/ if (!file) { LL_WARNS() << "Error opening " << filename << LL_ENDL; @@ -832,7 +832,7 @@ bool LLPreviewNotecard::loadNotecardText(const std::string& filename) bool LLPreviewNotecard::writeToFile(const std::string& filename) { - LLFILE* fp = LLFile::fopen(filename, TEXT("wb")); + LLFILE* fp = LLFile::fopen(filename, LLFILE_MODE("wb")); if (!fp) { LL_WARNS() << "Unable to write to " << filename << LL_ENDL; diff --git a/indra/newview/llpreviewscript.cpp b/indra/newview/llpreviewscript.cpp index c73976e540..53d0a712a8 100644 --- a/indra/newview/llpreviewscript.cpp +++ b/indra/newview/llpreviewscript.cpp @@ -632,7 +632,7 @@ bool LLScriptEdCore::loadScriptText(const std::string& filename) return false; } - LLFILE* file = LLFile::fopen(filename, TEXT("rb")); /*Flawfinder: ignore*/ + LLFILE* file = LLFile::fopen(filename, LLFILE_MODE("rb")); /*Flawfinder: ignore*/ if (!file) { LL_WARNS() << "Error opening " << filename << LL_ENDL; @@ -663,7 +663,7 @@ bool LLScriptEdCore::loadScriptText(const std::string& filename) bool LLScriptEdCore::writeToFile(const std::string& filename) { - LLFILE* fp = LLFile::fopen(filename, TEXT("wb")); + LLFILE* fp = LLFile::fopen(filename, LLFILE_MODE("wb")); if (!fp) { LL_WARNS() << "Unable to write to " << filename << LL_ENDL; diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index 37609f74ed..2cb2a7f8d5 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -587,7 +587,7 @@ bool idle_startup() std::string message_template_path = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS,"message_template.msg"); LLFILE* found_template = NULL; - found_template = LLFile::fopen(message_template_path, TEXT("r")); /* Flawfinder: ignore */ + found_template = LLFile::fopen(message_template_path, LLFILE_MODE("r")); /* Flawfinder: ignore */ #if LL_WINDOWS // On the windows dev builds, unpackaged, the message_template.msg @@ -596,7 +596,7 @@ bool idle_startup() if (!found_template) { message_template_path = gDirUtilp->getExpandedFilename(LL_PATH_EXECUTABLE, "app_settings", "message_template.msg"); - found_template = LLFile::fopen(message_template_path.c_str(), TEXT("r")); /* Flawfinder: ignore */ + found_template = LLFile::fopen(message_template_path.c_str(), LLFILE_MODE("r")); /* Flawfinder: ignore */ } #elif LL_DARWIN // On Mac dev builds, message_template.msg lives in: @@ -606,7 +606,7 @@ bool idle_startup() message_template_path = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "message_template.msg"); - found_template = LLFile::fopen(message_template_path.c_str(), TEXT("r")); /* Flawfinder: ignore */ + found_template = LLFile::fopen(message_template_path.c_str(), LLFILE_MODE("r")); /* Flawfinder: ignore */ } #endif diff --git a/indra/newview/lltoolbarview.cpp b/indra/newview/lltoolbarview.cpp index d1e36676af..c401a00fd7 100644 --- a/indra/newview/lltoolbarview.cpp +++ b/indra/newview/lltoolbarview.cpp @@ -420,7 +420,7 @@ void LLToolBarView::saveToolbars() const if(!output_node->isNull()) { const std::string& filename = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, "toolbars.xml"); - LLFILE *fp = LLFile::fopen(filename, TEXT("w")); + LLFILE *fp = LLFile::fopen(filename, LLFILE_MODE("w")); if (fp != NULL) { LLXMLNode::writeHeaderToFile(fp); diff --git a/indra/newview/llviewerassetstorage.cpp b/indra/newview/llviewerassetstorage.cpp index c28f3dc73a..867d47c893 100644 --- a/indra/newview/llviewerassetstorage.cpp +++ b/indra/newview/llviewerassetstorage.cpp @@ -279,7 +279,7 @@ void LLViewerAssetStorage::storeAssetData( LL_DEBUGS("AssetStorage") << "ASSET_ID: " << asset_id << LL_ENDL; S32 size = 0; - LLFILE* fp = LLFile::fopen(filename, TEXT("rb")); + LLFILE* fp = LLFile::fopen(filename, LLFILE_MODE("rb")); if (fp) { fseek(fp, 0, SEEK_END); diff --git a/indra/newview/llviewerinput.cpp b/indra/newview/llviewerinput.cpp index 9b39f7b0e9..5741d7f5fb 100644 --- a/indra/newview/llviewerinput.cpp +++ b/indra/newview/llviewerinput.cpp @@ -1430,7 +1430,7 @@ S32 LLViewerInput::loadBindingsXML(const std::string& filename) // file in app_settings is supposed to be up to date // this is only for the file from user_settings LL_INFOS("ViewerInput") << "Updating file " << filename << " to a newer version" << LL_ENDL; - LLFILE *fp = LLFile::fopen(filename, TEXT("w")); + LLFILE *fp = LLFile::fopen(filename, LLFILE_MODE("w")); if (fp != NULL) { LLXMLNode::writeHeaderToFile(fp); diff --git a/indra/newview/llviewermenufile.cpp b/indra/newview/llviewermenufile.cpp index a8ed2da9e0..423bb5f31d 100644 --- a/indra/newview/llviewermenufile.cpp +++ b/indra/newview/llviewermenufile.cpp @@ -1161,7 +1161,7 @@ void handle_compress_image() // so doing dirty, but OS independent fopen and fseek size_t get_file_size(std::string &filename) { - LLFILE* file = LLFile::fopen(filename, TEXT("rb")); /*Flawfinder: ignore*/ + LLFILE* file = LLFile::fopen(filename, LLFILE_MODE("rb")); /*Flawfinder: ignore*/ if (!file) { LL_WARNS() << "Error opening " << filename << LL_ENDL; diff --git a/indra/newview/llviewerstatsrecorder.cpp b/indra/newview/llviewerstatsrecorder.cpp index a2141f4eed..a183d7c8de 100644 --- a/indra/newview/llviewerstatsrecorder.cpp +++ b/indra/newview/llviewerstatsrecorder.cpp @@ -194,7 +194,7 @@ void LLViewerStatsRecorder::writeToLog( F32 interval ) // Open the data file makeStatsFileName(); - mStatsFile = LLFile::fopen(mStatsFileName, TEXT("wb")); + mStatsFile = LLFile::fopen(mStatsFileName, LLFILE_MODE("wb")); if (mStatsFile) { -- cgit v1.3 From 05ee4d295c2fa7fbc34aa82354c424b017558759 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev <117672381+akleshchev@users.noreply.github.com> Date: Thu, 4 Jun 2026 22:16:46 +0300 Subject: #5881 Optimize inventory cache loading --- indra/llinventory/llinventory.cpp | 318 +++++++++++++++++++------------------ indra/newview/llinventorymodel.cpp | 15 +- 2 files changed, 176 insertions(+), 157 deletions(-) (limited to 'indra/newview/llinventorymodel.cpp') diff --git a/indra/llinventory/llinventory.cpp b/indra/llinventory/llinventory.cpp index 2f60e3bead..a972967abe 100644 --- a/indra/llinventory/llinventory.cpp +++ b/indra/llinventory/llinventory.cpp @@ -1044,171 +1044,185 @@ bool LLInventoryItem::fromLLSD(const LLSD& sd, bool is_new) end = sd.endMap(); for (i = sd.beginMap(); i != end; ++i) { - if (i->first == INV_ITEM_ID_LABEL) - { - mUUID = i->second; - continue; - } - - if (i->first == INV_PARENT_ID_LABEL) - { - mParentUUID = i->second; - continue; - } - - if (i->first == INV_THUMBNAIL_LABEL) - { - const LLSD &thumbnail_map = i->second; - if (thumbnail_map.has(INV_ASSET_ID_LABEL)) - { - mThumbnailUUID = thumbnail_map[INV_ASSET_ID_LABEL]; - } - /* Example: - asset_id - acc0ec86 - 17f2 - 4b92 - ab41 - 6718b1f755f7 - perms - 8 - service - 3 - version - 1 - */ - continue; - } - - if (i->first == INV_THUMBNAIL_ID_LABEL) - { - mThumbnailUUID = i->second.asUUID(); - continue; - } + // Use string length as a fast pre-filter before string comparison + const std::string& key = i->first; + const LLSD& value = i->second; + const size_t key_len = key.length(); - if (i->first == INV_FAVORITE_LABEL) + switch (key_len) { - const LLSD& favorite_map = i->second; - if (favorite_map.has(INV_TOGGLED_LABEL)) - { - mFavorite = favorite_map[INV_TOGGLED_LABEL].asBoolean(); - } - continue; - } - - if (i->first == INV_PERMISSIONS_LABEL) - { - mPermissions.importLLSD(i->second); - continue; - } - - if (i->first == INV_SALE_INFO_LABEL) - { - // Sale info used to contain next owner perm. It is now in - // the permissions. Thus, we read that out, and fix legacy - // objects. It's possible this op would fail, but it - // should pick up the vast majority of the tasks. - bool has_perm_mask = false; - U32 perm_mask = 0; - if (!mSaleInfo.fromLLSD(i->second, has_perm_mask, perm_mask)) - { - return false; - } - if (has_perm_mask) - { - if (perm_mask == PERM_NONE) + case 4: // "name", "desc", "type" + if (key == INV_NAME_LABEL) // "name" { - perm_mask = mPermissions.getMaskOwner(); + mName = value.asString(); + LLStringUtil::replaceNonstandardASCII(mName, ' '); + LLStringUtil::replaceChar(mName, '|', ' '); + continue; } - // fair use fix. - if (!(perm_mask & PERM_COPY)) + if (key == INV_DESC_LABEL) // "desc" { - perm_mask |= PERM_TRANSFER; + mDescription = value.asString(); + LLStringUtil::replaceNonstandardASCII(mDescription, ' '); + continue; } - mPermissions.setMaskNext(perm_mask); - } - continue; - } - - if (i->first == INV_SHADOW_ID_LABEL) - { - mAssetUUID = i->second; - LLXORCipher cipher(MAGIC_ID.mData, UUID_BYTES); - cipher.decrypt(mAssetUUID.mData, UUID_BYTES); - continue; - } - - if (i->first == INV_ASSET_ID_LABEL) - { - mAssetUUID = i->second; - continue; - } + if (key == INV_ASSET_TYPE_LABEL) // "type" + { + if (value.isString()) + { + mType = LLAssetType::lookup(value.asStringRef().c_str()); + } + else if (value.isInteger()) + { + S8 type = (U8)value.asInteger(); + mType = static_cast(type); + } + continue; + } + break; - if (i->first == INV_LINKED_ID_LABEL) - { - mAssetUUID = i->second; - continue; - } + case 5: // "flags" + if (key == INV_FLAGS_LABEL) + { + if (value.isBinary()) + { + mFlags = ll_U32_from_sd(value); + } + else if (value.isInteger()) + { + mFlags = value.asInteger(); + } + continue; + } + break; - if (i->first == INV_ASSET_TYPE_LABEL) - { - LLSD const &label = i->second; - if (label.isString()) - { - mType = LLAssetType::lookup(label.asStringRef().c_str()); - } - else if (label.isInteger()) - { - S8 type = (U8) label.asInteger(); - mType = static_cast(type); - } - continue; - } + case 7: // "item_id" + if (key == INV_ITEM_ID_LABEL) + { + mUUID = value; + continue; + } + break; - if (i->first == INV_INVENTORY_TYPE_LABEL) - { - LLSD const &label = i->second; - if (label.isString()) - { - mInventoryType = LLInventoryType::lookup(label.asStringRef().c_str()); - } - else if (label.isInteger()) - { - S8 type = (U8) label.asInteger(); - mInventoryType = static_cast(type); - } - continue; - } + case 8: // "asset_id", "inv_type" + if (key == INV_ASSET_ID_LABEL) + { + mAssetUUID = value; + continue; + } + if (key == INV_INVENTORY_TYPE_LABEL) // "inv_type" + { + if (value.isString()) + { + mInventoryType = LLInventoryType::lookup(value.asStringRef().c_str()); + } + else if (value.isInteger()) + { + S8 type = (U8)value.asInteger(); + mInventoryType = static_cast(type); + } + continue; + } + if (key == INV_FAVORITE_LABEL) // "favorite" + { + if (value.has(INV_TOGGLED_LABEL)) + { + mFavorite = value[INV_TOGGLED_LABEL].asBoolean(); + } + continue; + } + break; - if (i->first == INV_FLAGS_LABEL) - { - LLSD const &label = i->second; - if (label.isBinary()) - { - mFlags = ll_U32_from_sd(label); - } - else if (label.isInteger()) - { - mFlags = label.asInteger(); - } - continue; - } + case 9: // "parent_id", "shadow_id", "linked_id", "sale_info", "thumbnail" + if (key == INV_PARENT_ID_LABEL) + { + mParentUUID = value; + continue; + } + if (key == INV_SHADOW_ID_LABEL) + { + mAssetUUID = value; + LLXORCipher cipher(MAGIC_ID.mData, UUID_BYTES); + cipher.decrypt(mAssetUUID.mData, UUID_BYTES); + continue; + } + if (key == INV_LINKED_ID_LABEL) + { + mAssetUUID = value; + continue; + } + if (key == INV_SALE_INFO_LABEL) + { + // Sale info used to contain next owner perm. It is now in + // the permissions. Thus, we read that out, and fix legacy + // objects. It's possible this op would fail, but it + // should pick up the vast majority of the tasks. + bool has_perm_mask = false; + U32 perm_mask = 0; + if (!mSaleInfo.fromLLSD(value, has_perm_mask, perm_mask)) + { + return false; + } + if (has_perm_mask) + { + if (perm_mask == PERM_NONE) + { + perm_mask = mPermissions.getMaskOwner(); + } + // fair use fix. + if (!(perm_mask & PERM_COPY)) + { + perm_mask |= PERM_TRANSFER; + } + mPermissions.setMaskNext(perm_mask); + } + continue; + } + if (key == INV_THUMBNAIL_LABEL) + { + if (value.has(INV_ASSET_ID_LABEL)) + { + mThumbnailUUID = value[INV_ASSET_ID_LABEL]; + } + /* Example: + asset_id + acc0ec86 - 17f2 - 4b92 - ab41 - 6718b1f755f7 + perms + 8 + service + 3 + version + 1 + */ + continue; + } + break; + case 10: // "created_at" + if (key == INV_CREATION_DATE_LABEL) + { + mCreationDate = value.asInteger(); + continue; + } + break; - if (i->first == INV_NAME_LABEL) - { - mName = i->second.asString(); - LLStringUtil::replaceNonstandardASCII(mName, ' '); - LLStringUtil::replaceChar(mName, '|', ' '); - continue; - } + case 11: // "permissions" + if (key == INV_PERMISSIONS_LABEL) + { + mPermissions.importLLSD(value); + continue; + } + break; - if (i->first == INV_DESC_LABEL) - { - mDescription = i->second.asString(); - LLStringUtil::replaceNonstandardASCII(mDescription, ' '); - continue; - } + case 12: // "thumbnail_id" + if (key == INV_THUMBNAIL_ID_LABEL) + { + mThumbnailUUID = value.asUUID(); + continue; + } + break; - if (i->first == INV_CREATION_DATE_LABEL) - { - mCreationDate = i->second.asInteger(); - continue; + default: + // Unknown field - skip + break; } } diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index 8b9aad4641..c72f1d2c35 100644 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -2719,10 +2719,11 @@ bool LLInventoryModel::loadSkeleton( for(LLSD::array_const_iterator it = options.beginArray(), end = options.endArray(); it != end; ++it) { - LLSD name = (*it)["name"]; - LLSD folder_id = (*it)["folder_id"]; - LLSD parent_id = (*it)["parent_id"]; - LLSD version = (*it)["version"]; + const LLSD &folder = *it; + const LLSD &name = folder["name"]; + const LLSD &folder_id = folder["folder_id"]; + const LLSD &parent_id = folder["parent_id"]; + const LLSD &version = folder["version"]; if(name.isDefined() && folder_id.isDefined() && parent_id.isDefined() @@ -2736,7 +2737,7 @@ bool LLInventoryModel::loadSkeleton( cat->setParent(parent_id.asUUID()); LLFolderType::EType preferred_type = LLFolderType::FT_NONE; - LLSD type_default = (*it)["type_default"]; + const LLSD &type_default = folder["type_default"]; if(type_default.isDefined()) { preferred_type = (LLFolderType::EType)type_default.asInteger(); @@ -3454,6 +3455,8 @@ bool LLInventoryModel::loadFromFile(const std::string& filename, const LLSD& llsd_cats = inventory["categories"]; if (llsd_cats.isArray()) { + size_t cats_count = llsd_cats.size(); + categories.reserve(cats_count); LLSD::array_const_iterator iter = llsd_cats.beginArray(); LLSD::array_const_iterator end = llsd_cats.endArray(); for (; iter != end; ++iter) @@ -3472,6 +3475,8 @@ bool LLInventoryModel::loadFromFile(const std::string& filename, const LLSD& llsd_items = inventory["items"]; if (llsd_items.isArray()) { + size_t items_count = llsd_items.size(); + items.reserve(items_count); LLSD::array_const_iterator iter = llsd_items.beginArray(); LLSD::array_const_iterator end = llsd_items.endArray(); for (; iter != end; ++iter) -- cgit v1.3 From 0f0e7e85076df6c71ea23b4bae2b0ed264e52291 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev <117672381+akleshchev@users.noreply.github.com> Date: Mon, 20 Jul 2026 20:39:09 +0300 Subject: #6014 Offload inventory cache packing onto a thread --- indra/newview/llappviewer.cpp | 2 ++ indra/newview/llinventorymodel.cpp | 58 ++++++++++++++++++++++++++++++++------ indra/newview/llinventorymodel.h | 6 ++++ 3 files changed, 58 insertions(+), 8 deletions(-) (limited to 'indra/newview/llinventorymodel.cpp') diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 553517472e..6a236e9b2e 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -2160,6 +2160,8 @@ bool LLAppViewer::cleanup() SUBSYSTEM_CLEANUP(LLProxy); LLCore::LLHttp::cleanup(); + LLInventoryModel::waitForPendingCacheWrites(); + ll_close_fail_log(); LLError::LLCallStacks::cleanup(); diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index c72f1d2c35..f85d0eebae 100644 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -82,6 +82,7 @@ const S32 LLInventoryModel::sCurrentInvCacheVersion = 5; bool LLInventoryModel::sFirstTimeInViewer2 = true; S32 LLInventoryModel::sPendingSystemFolders = 0; +std::vector LLInventoryModel::sPendingCacheThreads; ///---------------------------------------------------------------------------- /// Local function declarations, constants, enums, and typedefs @@ -465,6 +466,7 @@ LLInventoryModel::~LLInventoryModel() void LLInventoryModel::cleanupInventory() { + LL_PROFILE_ZONE_SCOPED; empty(); // Deleting one observer might erase others from the list, so always pop off the front while (!mObservers.empty()) @@ -2367,6 +2369,7 @@ void LLInventoryModel::cache( const LLUUID& parent_folder_id, const LLUUID& agent_id) { + LL_PROFILE_ZONE_SCOPED; LL_DEBUGS(LOG_INV) << "Caching " << parent_folder_id << " for " << agent_id << LL_ENDL; LLViewerInventoryCategory* root_cat = getCategory(parent_folder_id); @@ -2401,18 +2404,57 @@ void LLInventoryModel::cache( } std::string gzip_filename = getInvCacheAddres(agent_id); gzip_filename.append(".gz"); - if(gzip_file(temp_file, gzip_filename)) - { - LL_DEBUGS(LOG_INV) << "Successfully compressed " << temp_file << " to " << gzip_filename << LL_ENDL; - LLFile::remove(temp_file); - } - else + + // Launch detached packing thread + // Main thread is the only one modifying sPendingCacheThreads + sPendingCacheThreads.emplace_back( + [temp_file, gzip_filename]() { + LLTimer gzip_timer; + + if (gzip_file(temp_file, gzip_filename)) + { + F32 gzip_time = gzip_timer.getElapsedTimeF32(); + LL_DEBUGS(LOG_INV) << "Successfully compressed " << temp_file + << " to " << gzip_filename + << " in " << gzip_time << "s (async)" << LL_ENDL; + LLFile::remove(temp_file); + } + else + { + LL_WARNS(LOG_INV) << "Unable to compress " << temp_file + << " into " << gzip_filename << LL_ENDL; + } + }); +} + +void LLInventoryModel::waitForPendingCacheWrites() +{ + LL_PROFILE_ZONE_SCOPED; + + // By this point all threads should have already been added, + // viewer is shutting down, main thread is the only one to + // modify sPendingCacheThreads + if (!sPendingCacheThreads.empty()) { - LL_WARNS(LOG_INV) << "Unable to compress " << temp_file << " into " << gzip_filename << LL_ENDL; + LL_DEBUGS(LOG_INV) << "Waiting for " << sPendingCacheThreads.size() + << " inventory cache compression thread(s) to complete..." << LL_ENDL; + + LLTimer wait_timer; + + for (auto& thread : sPendingCacheThreads) + { + if (thread.joinable()) + { + thread.join(); + } + } + + F32 wait_time = wait_timer.getElapsedTimeF32(); + LL_INFOS(LOG_INV) << "Inventory cache compressions completed in " + << wait_time << "s" << LL_ENDL; } } - void LLInventoryModel::addCategory(LLViewerInventoryCategory* category) { //LL_INFOS(LOG_INV) << "LLInventoryModel::addCategory()" << LL_ENDL; diff --git a/indra/newview/llinventorymodel.h b/indra/newview/llinventorymodel.h index 05ada9121a..3a9e3fc3b0 100644 --- a/indra/newview/llinventorymodel.h +++ b/indra/newview/llinventorymodel.h @@ -195,7 +195,13 @@ public: // Call on logout to save a terse representation. void cache(const LLUUID& parent_folder_id, const LLUUID& agent_id); + + // Wait for any pending async cache operations to complete + static void waitForPendingCacheWrites(); private: + // Async gzip compression tracking + static std::vector sPendingCacheThreads; + // Information for tracking the actual inventory. We index this // information in a lot of different ways so we can access // the inventory using several different identifiers. -- cgit v1.3 From 4474d4f3fe115cec6b85dbb7f691da8d649fc258 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev <117672381+akleshchev@users.noreply.github.com> Date: Mon, 20 Jul 2026 22:11:01 +0300 Subject: #6014 Make inventory caching flat instead of recursive --- indra/newview/llinventorymodel.cpp | 167 ++++++++++++++++++++++++------------- indra/newview/llinventorymodel.h | 3 - 2 files changed, 110 insertions(+), 60 deletions(-) (limited to 'indra/newview/llinventorymodel.cpp') diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index f85d0eebae..e56db88cf9 100644 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -28,6 +28,7 @@ #include #include +#include #include "llinventorymodel.h" @@ -82,7 +83,7 @@ const S32 LLInventoryModel::sCurrentInvCacheVersion = 5; bool LLInventoryModel::sFirstTimeInViewer2 = true; S32 LLInventoryModel::sPendingSystemFolders = 0; -std::vector LLInventoryModel::sPendingCacheThreads; +static std::vector sPendingCacheThreads; ///---------------------------------------------------------------------------- /// Local function declarations, constants, enums, and typedefs @@ -101,45 +102,6 @@ struct InventoryIDPtrLess } }; -class LLCanCache : public LLInventoryCollectFunctor -{ -public: - LLCanCache(LLInventoryModel* model) : mModel(model) {} - virtual ~LLCanCache() {} - virtual bool operator()(LLInventoryCategory* cat, LLInventoryItem* item); -protected: - LLInventoryModel* mModel; - std::set mCachedCatIDs; -}; - -bool LLCanCache::operator()(LLInventoryCategory* cat, LLInventoryItem* item) -{ - bool rv = false; - if(item) - { - if(mCachedCatIDs.find(item->getParentUUID()) != mCachedCatIDs.end()) - { - rv = true; - } - } - else if(cat) - { - // HACK: downcast - LLViewerInventoryCategory* c = (LLViewerInventoryCategory*)cat; - if(c->getVersion() != LLViewerInventoryCategory::VERSION_UNKNOWN) - { - S32 descendents_server = c->getDescendentCount(); - S32 descendents_actual = c->getViewerDescendentCount(); - if(descendents_server == descendents_actual) - { - mCachedCatIDs.insert(c->getUUID()); - rv = true; - } - } - } - return rv; -} - struct InventoryCallbackInfo { InventoryCallbackInfo(U32 callback, const LLUUID& inv_id) : @@ -2372,20 +2334,98 @@ void LLInventoryModel::cache( LL_PROFILE_ZONE_SCOPED; LL_DEBUGS(LOG_INV) << "Caching " << parent_folder_id << " for " << agent_id << LL_ENDL; + LLViewerInventoryCategory* root_cat = getCategory(parent_folder_id); - if(!root_cat) return; + if (!root_cat) + { + LL_WARNS(LOG_INV) << "Root category not found for " << parent_folder_id << LL_ENDL; + return; + } + cat_array_t categories; categories.push_back(root_cat); item_array_t items; - LLCanCache can_cache(this); - can_cache(root_cat, NULL); - collectDescendentsIf( - parent_folder_id, - categories, - items, - INCLUDE_TRASH, - can_cache); + // Lambda to check if a category should be cached + // Only cache if it has known version and matching descendent counts + auto should_cache_category = [](LLViewerInventoryCategory* cat) -> bool { + if (!cat || cat->getVersion() == LLViewerInventoryCategory::VERSION_UNKNOWN) + { + return false; + } + S32 descendents_server = cat->getDescendentCount(); + S32 descendents_actual = cat->getViewerDescendentCount(); + return (descendents_server == descendents_actual); + }; + + // Track which folders we've verified as cacheable descendants + std::unordered_set processed_folders; + processed_folders.insert(parent_folder_id); + + // First pass: identify all cacheable descendant folders + // Use pair of (folder_id, should_save_children) + std::deque> folders_to_check; + folders_to_check.push_back(std::make_pair(parent_folder_id, should_cache_category(root_cat))); + + while (!folders_to_check.empty()) + { + auto [current_id, save_children] = folders_to_check.front(); + folders_to_check.pop_front(); + + if (save_children) // else incorrect count or version + { + auto item_it = mParentChildItemTree.find(current_id); + if (item_it != mParentChildItemTree.end() && item_it->second) + { + for (LLViewerInventoryItem* item : *(item_it->second)) + { + if (item) + { + items.push_back(item); + } + } + } + } + + // Get child categories directly from the parent-child tree + auto cat_it = mParentChildCategoryTree.find(current_id); + if (cat_it != mParentChildCategoryTree.end() && cat_it->second) + { + for (LLViewerInventoryCategory* child_cat : *(cat_it->second)) + { + if (!child_cat) + { + continue; + } + + // Verify ownership matches (library vs agent inventory) + if (child_cat->getOwnerID() != root_cat->getOwnerID()) + { + LL_WARNS(LOG_INV) << "Owner mismatch in category tree: expected " + << root_cat->getOwnerID() << " got " + << child_cat->getOwnerID() << " for category " + << child_cat->getName() << LL_ENDL; + continue; + } + + const LLUUID& child_id = child_cat->getUUID(); + + // Only process each folder once + if (processed_folders.insert(child_id).second) + { + if (should_cache_category(child_cat)) + { + categories.push_back(child_cat); + folders_to_check.push_back(std::make_pair(child_id, true)); + } + else + { + folders_to_check.push_back(std::make_pair(child_id, false)); + } + } + } + } + } if (categories.empty() && items.empty()) { @@ -2405,10 +2445,15 @@ void LLInventoryModel::cache( std::string gzip_filename = getInvCacheAddres(agent_id); gzip_filename.append(".gz"); - // Launch detached packing thread + if (sPendingCacheThreads.empty()) + { + LL_INFOS(LOG_INV) << "Inventory cache compression started" << LL_ENDL; + } + + // Launch background packing thread // Main thread is the only one modifying sPendingCacheThreads - sPendingCacheThreads.emplace_back( - [temp_file, gzip_filename]() { + auto compress_cache = [temp_file, gzip_filename]() + { LLTimer gzip_timer; if (gzip_file(temp_file, gzip_filename)) @@ -2416,7 +2461,7 @@ void LLInventoryModel::cache( F32 gzip_time = gzip_timer.getElapsedTimeF32(); LL_DEBUGS(LOG_INV) << "Successfully compressed " << temp_file << " to " << gzip_filename - << " in " << gzip_time << "s (async)" << LL_ENDL; + << " in " << gzip_time << "s" << LL_ENDL; LLFile::remove(temp_file); } else @@ -2424,7 +2469,17 @@ void LLInventoryModel::cache( LL_WARNS(LOG_INV) << "Unable to compress " << temp_file << " into " << gzip_filename << LL_ENDL; } - }); + }; + + try + { + sPendingCacheThreads.emplace_back(compress_cache); + } + catch (...) + { + LL_WARNS(LOG_INV) << "Failed to start inventory cache compression thread; running compression synchronously" << LL_ENDL; + compress_cache(); + } } void LLInventoryModel::waitForPendingCacheWrites() @@ -2449,9 +2504,7 @@ void LLInventoryModel::waitForPendingCacheWrites() } } - F32 wait_time = wait_timer.getElapsedTimeF32(); - LL_INFOS(LOG_INV) << "Inventory cache compressions completed in " - << wait_time << "s" << LL_ENDL; + LL_INFOS(LOG_INV) << "Inventory cache compression completed" << LL_ENDL; } } diff --git a/indra/newview/llinventorymodel.h b/indra/newview/llinventorymodel.h index 3a9e3fc3b0..2c516f6a86 100644 --- a/indra/newview/llinventorymodel.h +++ b/indra/newview/llinventorymodel.h @@ -199,9 +199,6 @@ public: // Wait for any pending async cache operations to complete static void waitForPendingCacheWrites(); private: - // Async gzip compression tracking - static std::vector sPendingCacheThreads; - // Information for tracking the actual inventory. We index this // information in a lot of different ways so we can access // the inventory using several different identifiers. -- cgit v1.3 From baf6a330f51e9521625e265dafa4766cc9236a60 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev <117672381+akleshchev@users.noreply.github.com> Date: Tue, 21 Jul 2026 16:47:59 +0300 Subject: #6014 Update splash screen --- indra/newview/llappviewer.cpp | 4 +++- indra/newview/llinventorymodel.cpp | 1 + indra/newview/skins/default/xui/en/strings.xml | 2 ++ 3 files changed, 6 insertions(+), 1 deletion(-) (limited to 'indra/newview/llinventorymodel.cpp') diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 6a236e9b2e..0224f1613b 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -2058,7 +2058,7 @@ bool LLAppViewer::cleanup() } LLSplashScreen::show(); - LLSplashScreen::update(LLTrans::getString("ShuttingDown")); + LLSplashScreen::update(LLTrans::getString("ShutdownCleanup")); LL_INFOS() << "Cleaning up Keyboard & Joystick" << LL_ENDL; @@ -2160,7 +2160,9 @@ bool LLAppViewer::cleanup() SUBSYSTEM_CLEANUP(LLProxy); LLCore::LLHttp::cleanup(); + LLSplashScreen::update(LLTrans::getString("CompressingInventoryCache")); LLInventoryModel::waitForPendingCacheWrites(); + LLSplashScreen::update(LLTrans::getString("ShuttingDown")); ll_close_fail_log(); diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index e56db88cf9..9a1cc3b122 100644 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -2454,6 +2454,7 @@ void LLInventoryModel::cache( // Main thread is the only one modifying sPendingCacheThreads auto compress_cache = [temp_file, gzip_filename]() { + LL_PROFILE_ZONE_NAMED("inv cache compression"); LLTimer gzip_timer; if (gzip_file(temp_file, gzip_filename)) diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml index e44a18ae79..ce86352643 100644 --- a/indra/newview/skins/default/xui/en/strings.xml +++ b/indra/newview/skins/default/xui/en/strings.xml @@ -206,6 +206,8 @@ If you feel this is an error, please contact support@secondlife.com This region may be experiencing trouble. Please check your connection to the Internet. Saving your settings... Logging out... + Compressing inventory cache... + Releasing resources... Shutting down... You have been disconnected from the region you were in. You were sent to an invalid region. -- cgit v1.3 From 3cd27c658a4aa94f68cd2f5c96e638a28d2c4297 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev <117672381+akleshchev@users.noreply.github.com> Date: Tue, 21 Jul 2026 17:36:59 +0300 Subject: #6014 Inventory cache tweaks --- indra/newview/llappviewer.cpp | 6 +++--- indra/newview/llinventorymodel.cpp | 26 +++++++++++++------------- 2 files changed, 16 insertions(+), 16 deletions(-) (limited to 'indra/newview/llinventorymodel.cpp') diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 0224f1613b..5a1a4b8258 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -1749,15 +1749,15 @@ bool LLAppViewer::cleanup() // Give any remaining SLPlugin instances a chance to exit cleanly. LLPluginProcessParent::shutdown(); - disconnectViewer(); - if (LLWatchdog::instanceExists()) { // Signal a stop early, so that it will be out - // of sleep loop by the time we get to clean it. + // of 1s sleep loop by the time we get to clean it. LLWatchdog::getInstance()->shutdown(); } + disconnectViewer(); + LLViewerCamera::deleteSingleton(); LL_INFOS() << "Viewer disconnected" << LL_ENDL; diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index 9a1cc3b122..dbcade88c2 100644 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -2485,28 +2485,28 @@ void LLInventoryModel::cache( void LLInventoryModel::waitForPendingCacheWrites() { + if (sPendingCacheThreads.empty()) + { + return; + } LL_PROFILE_ZONE_SCOPED; // By this point all threads should have already been added, // viewer is shutting down, main thread is the only one to // modify sPendingCacheThreads - if (!sPendingCacheThreads.empty()) - { - LL_DEBUGS(LOG_INV) << "Waiting for " << sPendingCacheThreads.size() - << " inventory cache compression thread(s) to complete..." << LL_ENDL; - - LLTimer wait_timer; + LL_DEBUGS(LOG_INV) << "Waiting for " << sPendingCacheThreads.size() + << " inventory cache compression thread(s) to complete..." << LL_ENDL; - for (auto& thread : sPendingCacheThreads) + for (auto& thread : sPendingCacheThreads) + { + if (thread.joinable()) { - if (thread.joinable()) - { - thread.join(); - } + thread.join(); } - - LL_INFOS(LOG_INV) << "Inventory cache compression completed" << LL_ENDL; } + sPendingCacheThreads.clear(); + + LL_INFOS(LOG_INV) << "Inventory cache compression completed" << LL_ENDL; } void LLInventoryModel::addCategory(LLViewerInventoryCategory* category) -- cgit v1.3 From 2a75b42f164501e44ea2f35361812f87935c225e Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev <117672381+akleshchev@users.noreply.github.com> Date: Tue, 21 Jul 2026 19:12:39 +0300 Subject: #6014 Speedup cleanupInventory --- indra/llinventory/llinventory.cpp | 22 ++++++++++++++-------- indra/newview/llinventorymodel.cpp | 20 +++++++++++--------- 2 files changed, 25 insertions(+), 17 deletions(-) (limited to 'indra/newview/llinventorymodel.cpp') diff --git a/indra/llinventory/llinventory.cpp b/indra/llinventory/llinventory.cpp index a972967abe..d63709d22f 100644 --- a/indra/llinventory/llinventory.cpp +++ b/indra/llinventory/llinventory.cpp @@ -983,12 +983,14 @@ void LLInventoryItem::asLLSD( LLSD& sd ) const if (mThumbnailUUID.notNull()) { - sd[INV_THUMBNAIL_LABEL] = LLSD().with(INV_ASSET_ID_LABEL, mThumbnailUUID); + LLSD& thumbnail = sd[INV_THUMBNAIL_LABEL]; + thumbnail[INV_ASSET_ID_LABEL] = mThumbnailUUID; } if (mFavorite) { - sd[INV_FAVORITE_LABEL] = LLSD().with(INV_TOGGLED_LABEL, mFavorite); + LLSD& favorite = sd[INV_FAVORITE_LABEL]; + favorite[INV_TOGGLED_LABEL] = mFavorite; } U32 mask = mPermissions.getMaskBase(); @@ -1005,7 +1007,7 @@ void LLInventoryItem::asLLSD( LLSD& sd ) const cipher.encrypt(shadow_id.mData, UUID_BYTES); sd[INV_SHADOW_ID_LABEL] = shadow_id; } - sd[INV_ASSET_TYPE_LABEL] = std::string(LLAssetType::lookup(mType)); + sd[INV_ASSET_TYPE_LABEL] = LLAssetType::lookup(mType); const std::string inv_type_str = LLInventoryType::lookup(mInventoryType); if(!inv_type_str.empty()) { @@ -1298,12 +1300,14 @@ LLSD LLInventoryCategory::asLLSD() const if (mThumbnailUUID.notNull()) { - sd[INV_THUMBNAIL_LABEL] = LLSD().with(INV_ASSET_ID_LABEL, mThumbnailUUID); + LLSD& thumbnail = sd[INV_THUMBNAIL_LABEL]; + thumbnail[INV_ASSET_ID_LABEL] = mThumbnailUUID; } if (mFavorite) { - sd[INV_FAVORITE_LABEL] = LLSD().with(INV_TOGGLED_LABEL, mFavorite); + LLSD& favorite = sd[INV_FAVORITE_LABEL]; + favorite[INV_TOGGLED_LABEL] = mFavorite; } return sd; @@ -1563,17 +1567,19 @@ void LLInventoryCategory::exportLLSD(LLSD& cat_data) const { cat_data[INV_FOLDER_ID_LABEL] = mUUID; cat_data[INV_PARENT_ID_LABEL] = mParentUUID; - cat_data[INV_ASSET_TYPE_LABEL] = std::string(LLAssetType::lookup(mType)); + cat_data[INV_ASSET_TYPE_LABEL] = LLAssetType::lookup(mType); cat_data[INV_PREFERRED_TYPE_LABEL] = LLFolderType::lookup(mPreferredType); cat_data[INV_NAME_LABEL] = mName; if (mThumbnailUUID.notNull()) { - cat_data[INV_THUMBNAIL_LABEL] = LLSD().with(INV_ASSET_ID_LABEL, mThumbnailUUID); + LLSD& thumbnail = cat_data[INV_THUMBNAIL_LABEL]; + thumbnail[INV_ASSET_ID_LABEL] = mThumbnailUUID; } if (mFavorite) { - cat_data[INV_FAVORITE_LABEL] = LLSD().with(INV_TOGGLED_LABEL, mFavorite); + LLSD& favorite = cat_data[INV_FAVORITE_LABEL]; + favorite[INV_TOGGLED_LABEL] = mFavorite; } } diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index dbcade88c2..7a80c46c73 100644 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -430,29 +430,31 @@ void LLInventoryModel::cleanupInventory() { LL_PROFILE_ZONE_SCOPED; empty(); - // Deleting one observer might erase others from the list, so always pop off the front - while (!mObservers.empty()) + // Deleting one observer might trigger removeObserver, so use a local copy + if (!mObservers.empty()) { - observer_list_t::iterator iter = mObservers.begin(); - LLInventoryObserver* observer = *iter; - mObservers.erase(iter); - delete observer; + observer_list_t observers_to_delete; + observers_to_delete.swap(mObservers); + + for (LLInventoryObserver* observer : observers_to_delete) + { + delete observer; + } } if (mBulkFecthCallbackSlot.connected()) { mBulkFecthCallbackSlot.disconnect(); } - mObservers.clear(); // Run down HTTP transport mHttpHeaders.reset(); mHttpOptions.reset(); delete mHttpRequestFG; - mHttpRequestFG = NULL; + mHttpRequestFG = nullptr; delete mHttpRequestBG; - mHttpRequestBG = NULL; + mHttpRequestBG = nullptr; } // This is a convenience function to check if one object has a parent -- cgit v1.3