diff options
45 files changed, 1650 insertions, 1193 deletions
| diff --git a/etc/message.xml b/etc/message.xml index 490d73e1b2..3445975545 100644 --- a/etc/message.xml +++ b/etc/message.xml @@ -685,20 +685,17 @@  			<key>EstateChangeInfo</key>  			<boolean>true</boolean> -			<key>FetchInventoryDescendents</key> +			<key>FetchInventoryDescendents2</key>  			<boolean>false</boolean> -			<key>WebFetchInventoryDescendents</key> -			<boolean>true</boolean> -		 -			<key>FetchInventory</key> -			<boolean>true</boolean> +			<key>FetchInventory2</key> +			<boolean>false</boolean> -			<key>FetchLibDescendents</key> -			<boolean>true</boolean> +			<key>FetchLibDescendents2</key> +			<boolean>false</boolean> -			<key>FetchLib</key> -			<boolean>true</boolean> +			<key>FetchLib2</key> +			<boolean>false</boolean>  			<key>UploadBakedTexture</key>  			<boolean>true</boolean> diff --git a/indra/cmake/Boost.cmake b/indra/cmake/Boost.cmake index 012d3c2ab2..7ce57a5572 100644 --- a/indra/cmake/Boost.cmake +++ b/indra/cmake/Boost.cmake @@ -10,8 +10,6 @@ if (STANDALONE)    set(BOOST_PROGRAM_OPTIONS_LIBRARY boost_program_options-mt)    set(BOOST_REGEX_LIBRARY boost_regex-mt)    set(BOOST_SIGNALS_LIBRARY boost_signals-mt) -  set(BOOST_SYSTEM_LIBRARY boost_system-mt) -  set(BOOST_FILESYSTEM_LIBRARY boost_filesystem-mt)  else (STANDALONE)    use_prebuilt_binary(boost)    set(Boost_INCLUDE_DIRS ${LIBS_PREBUILT_DIR}/include) @@ -28,12 +26,6 @@ else (STANDALONE)        set(BOOST_SIGNALS_LIBRARY             optimized libboost_signals-vc71-mt-s-${BOOST_VERSION}            debug libboost_signals-vc71-mt-sgd-${BOOST_VERSION}) -      set(BOOST_SYSTEM_LIBRARY  -          optimized libboost_system-vc71-mt-s-${BOOST_VERSION} -          debug libboost_system-vc71-mt-sgd-${BOOST_VERSION}) -      set(BOOST_FILESYSTEM_LIBRARY  -          optimized libboost_filesystem-vc71-mt-s-${BOOST_VERSION} -          debug libboost_filesystem-vc71-mt-sgd-${BOOST_VERSION})      else (MSVC71)        set(BOOST_PROGRAM_OPTIONS_LIBRARY             optimized libboost_program_options-vc80-mt-${BOOST_VERSION} @@ -44,24 +36,14 @@ else (STANDALONE)        set(BOOST_SIGNALS_LIBRARY             optimized libboost_signals-vc80-mt-${BOOST_VERSION}            debug libboost_signals-vc80-mt-gd-${BOOST_VERSION}) -      set(BOOST_SYSTEM_LIBRARY  -          optimized libboost_system-vc80-mt-${BOOST_VERSION} -          debug libboost_system-vc80-mt-gd-${BOOST_VERSION}) -      set(BOOST_FILESYSTEM_LIBRARY  -          optimized libboost_filesystem-vc80-mt-${BOOST_VERSION} -          debug libboost_filesystem-vc80-mt-gd-${BOOST_VERSION})      endif (MSVC71)    elseif (DARWIN)      set(BOOST_PROGRAM_OPTIONS_LIBRARY boost_program_options-xgcc40-mt)      set(BOOST_REGEX_LIBRARY boost_regex-xgcc40-mt)      set(BOOST_SIGNALS_LIBRARY boost_signals-xgcc40-mt) -    set(BOOST_SYSTEM_LIBRARY boost_system-xgcc40-mt) -    set(BOOST_FILESYSTEM_LIBRARY boost_filesystem-xgcc40-mt)    elseif (LINUX)      set(BOOST_PROGRAM_OPTIONS_LIBRARY boost_program_options-gcc41-mt)      set(BOOST_REGEX_LIBRARY boost_regex-gcc41-mt)      set(BOOST_SIGNALS_LIBRARY boost_signals-gcc41-mt) -    set(BOOST_SYSTEM_LIBRARY boost_system-gcc41-mt) -    set(BOOST_FILESYSTEM_LIBRARY boost_filesystem-gcc41-mt)    endif (WINDOWS)  endif (STANDALONE) diff --git a/indra/integration_tests/llui_libtest/llui_libtest.cpp b/indra/integration_tests/llui_libtest/llui_libtest.cpp index 217e26c3ca..c34115ee80 100644 --- a/indra/integration_tests/llui_libtest/llui_libtest.cpp +++ b/indra/integration_tests/llui_libtest/llui_libtest.cpp @@ -33,7 +33,6 @@  // linden library includes  #include "llcontrol.h"		// LLControlGroup  #include "lldir.h" -#include "lldiriterator.h"  #include "llerrorcontrol.h"  #include "llfloater.h"  #include "llfontfreetype.h" @@ -175,9 +174,7 @@ void export_test_floaters()  	std::string delim = gDirUtilp->getDirDelimiter();  	std::string xui_dir = get_xui_dir() + "en" + delim;  	std::string filename; - -	LLDirIterator iter(xui_dir, "floater_test_*.xml"); -	while (iter.next(filename)) +	while (gDirUtilp->getNextFileInDir(xui_dir, "floater_test_*.xml", filename))  	{  		if (filename.find("_new.xml") != std::string::npos)  		{ diff --git a/indra/linux_updater/linux_updater.cpp b/indra/linux_updater/linux_updater.cpp index 808ab3f64f..d909516bf8 100644 --- a/indra/linux_updater/linux_updater.cpp +++ b/indra/linux_updater/linux_updater.cpp @@ -33,7 +33,6 @@  #include "llerrorcontrol.h"  #include "llfile.h"  #include "lldir.h" -#include "lldiriterator.h"  #include "llxmlnode.h"  #include "lltrans.h" @@ -56,8 +55,6 @@ typedef struct _updater_app_state {  	std::string strings_dirs;  	std::string strings_file; -	LLDirIterator *image_dir_iter; -  	GtkWidget *window;  	GtkWidget *progress_bar;  	GtkWidget *image; @@ -111,7 +108,7 @@ bool translate_init(std::string comma_delim_path_list,  void updater_app_ui_init(void);  void updater_app_quit(UpdaterAppState *app_state);  void parse_args_and_init(int argc, char **argv, UpdaterAppState *app_state); -std::string next_image_filename(std::string& image_path, LLDirIterator& iter); +std::string next_image_filename(std::string& image_path);  void display_error(GtkWidget *parent, std::string title, std::string message);  BOOL install_package(std::string package_file, std::string destination);  BOOL spawn_viewer(UpdaterAppState *app_state); @@ -177,7 +174,7 @@ void updater_app_ui_init(UpdaterAppState *app_state)  		// load the first image  		app_state->image = gtk_image_new_from_file -			(next_image_filename(app_state->image_dir, *app_state->image_dir_iter).c_str()); +			(next_image_filename(app_state->image_dir).c_str());  		gtk_widget_set_size_request(app_state->image, 340, 310);  		gtk_container_add(GTK_CONTAINER(frame), app_state->image); @@ -208,7 +205,7 @@ gboolean rotate_image_cb(gpointer data)  	llassert(data != NULL);  	app_state = (UpdaterAppState *) data; -	filename = next_image_filename(app_state->image_dir, *app_state->image_dir_iter); +	filename = next_image_filename(app_state->image_dir);  	gdk_threads_enter();  	gtk_image_set_from_file(GTK_IMAGE(app_state->image), filename.c_str()); @@ -217,10 +214,10 @@ gboolean rotate_image_cb(gpointer data)  	return TRUE;  } -std::string next_image_filename(std::string& image_path, LLDirIterator& iter) +std::string next_image_filename(std::string& image_path)  {  	std::string image_filename; -	iter.next(image_filename); +	gDirUtilp->getNextFileInDir(image_path, "/*.jpg", image_filename);  	return image_path + "/" + image_filename;  } @@ -744,7 +741,6 @@ void parse_args_and_init(int argc, char **argv, UpdaterAppState *app_state)  		else if ((!strcmp(argv[i], "--image-dir")) && (++i < argc))  		{  			app_state->image_dir = argv[i]; -			app_state->image_dir_iter = new LLDirIterator(argv[i], "/*.jpg");  		}  		else if ((!strcmp(argv[i], "--dest")) && (++i < argc))  		{ @@ -829,7 +825,6 @@ int main(int argc, char **argv)  	}  	bool success = !app_state->failure; -	delete app_state->image_dir_iter;  	delete app_state;  	return success ? 0 : 1;  } diff --git a/indra/llcommon/llfile.cpp b/indra/llcommon/llfile.cpp index 8f02391e75..c32a776c3f 100644 --- a/indra/llcommon/llfile.cpp +++ b/indra/llcommon/llfile.cpp @@ -92,6 +92,17 @@ LLFILE*	LLFile::_fsopen(const std::string& filename, const char* mode, int shari  #endif  } +int	LLFile::close(LLFILE * file) +{ +	int ret_value = 0; +	if (file) +	{ +		ret_value = fclose(file); +	} +	return ret_value; +} + +  int	LLFile::remove(const std::string& filename)  {  #if	LL_WINDOWS diff --git a/indra/llcommon/llfile.h b/indra/llcommon/llfile.h index 4913af7cb5..dd7d36513a 100644 --- a/indra/llcommon/llfile.h +++ b/indra/llcommon/llfile.h @@ -71,6 +71,8 @@ public:  	static	LLFILE*	fopen(const std::string& filename,const char* accessmode);	/* Flawfinder: ignore */  	static	LLFILE*	_fsopen(const std::string& filename,const char* accessmode,int	sharingFlag); +	static	int		close(LLFILE * file); +  	// perms is a permissions mask like 0777 or 0700.  In most cases it will  	// be overridden by the user's umask.  It is ignored on Windows.  	static	int		mkdir(const std::string& filename, int perms = 0700); diff --git a/indra/llvfs/CMakeLists.txt b/indra/llvfs/CMakeLists.txt index b6d1ce61e5..569674ecf0 100644 --- a/indra/llvfs/CMakeLists.txt +++ b/indra/llvfs/CMakeLists.txt @@ -12,7 +12,6 @@ include_directories(  set(llvfs_SOURCE_FILES      lldir.cpp -    lldiriterator.cpp      lllfsthread.cpp      llpidlock.cpp      llvfile.cpp @@ -25,7 +24,6 @@ set(llvfs_HEADER_FILES      lldir.h      lldirguard.h -    lldiriterator.h      lllfsthread.h      llpidlock.h      llvfile.h @@ -62,11 +60,6 @@ list(APPEND llvfs_SOURCE_FILES ${llvfs_HEADER_FILES})  add_library (llvfs ${llvfs_SOURCE_FILES}) -target_link_libraries(llvfs -    ${BOOST_FILESYSTEM_LIBRARY} -    ${BOOST_SYSTEM_LIBRARY} -    ) -  if (DARWIN)    include(CMakeFindFrameworks)    find_library(CARBON_LIBRARY Carbon) diff --git a/indra/llvfs/lldir.cpp b/indra/llvfs/lldir.cpp index ab7d15dfef..64556bcb4c 100644 --- a/indra/llvfs/lldir.cpp +++ b/indra/llvfs/lldir.cpp @@ -40,8 +40,6 @@  #include "lltimer.h"	// ms_sleep()  #include "lluuid.h" -#include "lldiriterator.h" -  #if LL_WINDOWS  #include "lldir_win32.h"  LLDir_Win32 gDirUtil; @@ -85,9 +83,7 @@ S32 LLDir::deleteFilesInDir(const std::string &dirname, const std::string &mask)  	std::string filename;   	std::string fullpath;  	S32 result; - -	LLDirIterator iter(dirname, mask); -	while (iter.next(filename)) +	while (getNextFileInDir(dirname, mask, filename))  	{  		fullpath = dirname;  		fullpath += getDirDelimiter(); diff --git a/indra/llvfs/lldir.h b/indra/llvfs/lldir.h index 5ee8bdb542..42996fd051 100644 --- a/indra/llvfs/lldir.h +++ b/indra/llvfs/lldir.h @@ -75,6 +75,31 @@ class LLDir  // pure virtual functions  	virtual U32 countFilesInDir(const std::string &dirname, const std::string &mask) = 0; +    /// Walk the files in a directory, with file pattern matching +	virtual BOOL getNextFileInDir(const std::string& dirname, ///< directory path - must end in trailing slash! +                                  const std::string& mask,    ///< file pattern string (use "*" for all) +                                  std::string& fname          ///< output: found file name +                                  ) = 0; +    /**< +     * @returns true if a file was found, false if the entire directory has been scanned. +     * +     * @note that this function is NOT thread safe +     * +     * This function may not be used to scan part of a directory, then start a new search of a different +     * directory, and then restart the first search where it left off; the entire search must run to +     * completion or be abandoned - there is no restart. +     * +     * @bug: See http://jira.secondlife.com/browse/VWR-23697 +     *       and/or the tests in test/lldir_test.cpp +     *       This is known to fail with patterns that have both: +     *       a wildcard left of a . and more than one sequential ? right of a . +     *       the pattern foo.??x appears to work +     *       but *.??x or foo?.??x do not +     * +     * @todo this really should be rewritten as an iterator object, and the +     *       filtering should be done in a platform-independent way. +     */ +  	virtual std::string getCurPath() = 0;  	virtual BOOL fileExists(const std::string &filename) const = 0; diff --git a/indra/llvfs/lldir_linux.cpp b/indra/llvfs/lldir_linux.cpp index 4ba2f519b0..73f2336f94 100644 --- a/indra/llvfs/lldir_linux.cpp +++ b/indra/llvfs/lldir_linux.cpp @@ -242,6 +242,68 @@ U32 LLDir_Linux::countFilesInDir(const std::string &dirname, const std::string &  	return (file_count);  } +// get the next file in the directory +BOOL LLDir_Linux::getNextFileInDir(const std::string &dirname, const std::string &mask, std::string &fname) +{ +	glob_t g; +	BOOL result = FALSE; +	fname = ""; +	 +	if(!(dirname == mCurrentDir)) +	{ +		// different dir specified, close old search +		mCurrentDirIndex = -1; +		mCurrentDirCount = -1; +		mCurrentDir = dirname; +	} +	 +	std::string tmp_str; +	tmp_str = dirname; +	tmp_str += mask; + +	if(glob(tmp_str.c_str(), GLOB_NOSORT, NULL, &g) == 0) +	{ +		if(g.gl_pathc > 0) +		{ +			if((int)g.gl_pathc != mCurrentDirCount) +			{ +				// Number of matches has changed since the last search, meaning a file has been added or deleted. +				// Reset the index. +				mCurrentDirIndex = -1; +				mCurrentDirCount = g.gl_pathc; +			} +	 +			mCurrentDirIndex++; +	 +			if(mCurrentDirIndex < (int)g.gl_pathc) +			{ +//				llinfos << "getNextFileInDir: returning number " << mCurrentDirIndex << ", path is " << g.gl_pathv[mCurrentDirIndex] << llendl; + +				// The API wants just the filename, not the full path. +				//fname = g.gl_pathv[mCurrentDirIndex]; + +				char *s = strrchr(g.gl_pathv[mCurrentDirIndex], '/'); +				 +				if(s == NULL) +					s = g.gl_pathv[mCurrentDirIndex]; +				else if(s[0] == '/') +					s++; +					 +				fname = s; +				 +				result = TRUE; +			} +		} +		 +		globfree(&g); +	} +	 +	return(result); +} + + + +  std::string LLDir_Linux::getCurPath()  {  	char tmp_str[LL_MAX_PATH];	/* Flawfinder: ignore */  diff --git a/indra/llvfs/lldir_linux.h b/indra/llvfs/lldir_linux.h index ff4c48759a..451e81ae93 100644 --- a/indra/llvfs/lldir_linux.h +++ b/indra/llvfs/lldir_linux.h @@ -43,6 +43,7 @@ public:  public:	  	virtual std::string getCurPath();  	virtual U32 countFilesInDir(const std::string &dirname, const std::string &mask); +	virtual BOOL getNextFileInDir(const std::string &dirname, const std::string &mask, std::string &fname);  	/*virtual*/ BOOL fileExists(const std::string &filename) const;  	/*virtual*/ std::string getLLPluginLauncher(); diff --git a/indra/llvfs/lldir_mac.cpp b/indra/llvfs/lldir_mac.cpp index 2d039527c0..445285aa43 100644 --- a/indra/llvfs/lldir_mac.cpp +++ b/indra/llvfs/lldir_mac.cpp @@ -258,6 +258,67 @@ U32 LLDir_Mac::countFilesInDir(const std::string &dirname, const std::string &ma  	return (file_count);  } +// get the next file in the directory +BOOL LLDir_Mac::getNextFileInDir(const std::string &dirname, const std::string &mask, std::string &fname) +{ +	glob_t g; +	BOOL result = FALSE; +	fname = ""; +	 +	if(!(dirname == mCurrentDir)) +	{ +		// different dir specified, close old search +		mCurrentDirIndex = -1; +		mCurrentDirCount = -1; +		mCurrentDir = dirname; +	} +	 +	std::string tmp_str; +	tmp_str = dirname; +	tmp_str += mask; + +	if(glob(tmp_str.c_str(), GLOB_NOSORT, NULL, &g) == 0) +	{ +		if(g.gl_pathc > 0) +		{ +			if(g.gl_pathc != mCurrentDirCount) +			{ +				// Number of matches has changed since the last search, meaning a file has been added or deleted. +				// Reset the index. +				mCurrentDirIndex = -1; +				mCurrentDirCount = g.gl_pathc; +			} +	 +			mCurrentDirIndex++; +	 +			if(mCurrentDirIndex < g.gl_pathc) +			{ +//				llinfos << "getNextFileInDir: returning number " << mCurrentDirIndex << ", path is " << g.gl_pathv[mCurrentDirIndex] << llendl; + +				// The API wants just the filename, not the full path. +				//fname = g.gl_pathv[mCurrentDirIndex]; + +				char *s = strrchr(g.gl_pathv[mCurrentDirIndex], '/'); +				 +				if(s == NULL) +					s = g.gl_pathv[mCurrentDirIndex]; +				else if(s[0] == '/') +					s++; +					 +				fname = s; +				 +				result = TRUE; +			} +		} +		 +		globfree(&g); +	} +	 +	return(result); +} + + +  S32 LLDir_Mac::deleteFilesInDir(const std::string &dirname, const std::string &mask)  {  	glob_t g; diff --git a/indra/llvfs/lldir_mac.h b/indra/llvfs/lldir_mac.h index e60d5e41c2..4eac3c3ae6 100644 --- a/indra/llvfs/lldir_mac.h +++ b/indra/llvfs/lldir_mac.h @@ -43,6 +43,7 @@ public:  	virtual S32 deleteFilesInDir(const std::string &dirname, const std::string &mask);  	virtual std::string getCurPath();  	virtual U32 countFilesInDir(const std::string &dirname, const std::string &mask); +	virtual BOOL getNextFileInDir(const std::string &dirname, const std::string &mask, std::string &fname);  	virtual BOOL fileExists(const std::string &filename) const;  	/*virtual*/ std::string getLLPluginLauncher(); diff --git a/indra/llvfs/lldir_solaris.cpp b/indra/llvfs/lldir_solaris.cpp index 21f8c3acdb..515fd66b6e 100644 --- a/indra/llvfs/lldir_solaris.cpp +++ b/indra/llvfs/lldir_solaris.cpp @@ -260,6 +260,68 @@ U32 LLDir_Solaris::countFilesInDir(const std::string &dirname, const std::string  	return (file_count);  } +// get the next file in the directory +BOOL LLDir_Solaris::getNextFileInDir(const std::string &dirname, const std::string &mask, std::string &fname) +{ +	glob_t g; +	BOOL result = FALSE; +	fname = ""; +	 +	if(!(dirname == mCurrentDir)) +	{ +		// different dir specified, close old search +		mCurrentDirIndex = -1; +		mCurrentDirCount = -1; +		mCurrentDir = dirname; +	} +	 +	std::string tmp_str; +	tmp_str = dirname; +	tmp_str += mask; + +	if(glob(tmp_str.c_str(), GLOB_NOSORT, NULL, &g) == 0) +	{ +		if(g.gl_pathc > 0) +		{ +			if((int)g.gl_pathc != mCurrentDirCount) +			{ +				// Number of matches has changed since the last search, meaning a file has been added or deleted. +				// Reset the index. +				mCurrentDirIndex = -1; +				mCurrentDirCount = g.gl_pathc; +			} +	 +			mCurrentDirIndex++; +	 +			if(mCurrentDirIndex < (int)g.gl_pathc) +			{ +//				llinfos << "getNextFileInDir: returning number " << mCurrentDirIndex << ", path is " << g.gl_pathv[mCurrentDirIndex] << llendl; + +				// The API wants just the filename, not the full path. +				//fname = g.gl_pathv[mCurrentDirIndex]; + +				char *s = strrchr(g.gl_pathv[mCurrentDirIndex], '/'); +				 +				if(s == NULL) +					s = g.gl_pathv[mCurrentDirIndex]; +				else if(s[0] == '/') +					s++; +					 +				fname = s; +				 +				result = TRUE; +			} +		} +		 +		globfree(&g); +	} +	 +	return(result); +} + + + +  std::string LLDir_Solaris::getCurPath()  {  	char tmp_str[LL_MAX_PATH];	/* Flawfinder: ignore */  diff --git a/indra/llvfs/lldir_solaris.h b/indra/llvfs/lldir_solaris.h index f7e1a6301d..4a1794f539 100644 --- a/indra/llvfs/lldir_solaris.h +++ b/indra/llvfs/lldir_solaris.h @@ -43,6 +43,7 @@ public:  public:	  	virtual std::string getCurPath();  	virtual U32 countFilesInDir(const std::string &dirname, const std::string &mask); +	virtual BOOL getNextFileInDir(const std::string &dirname, const std::string &mask, std::string &fname);  	/*virtual*/ BOOL fileExists(const std::string &filename) const;  private: diff --git a/indra/llvfs/lldir_win32.cpp b/indra/llvfs/lldir_win32.cpp index 2f96fbbbc1..33718e520d 100644 --- a/indra/llvfs/lldir_win32.cpp +++ b/indra/llvfs/lldir_win32.cpp @@ -236,6 +236,67 @@ U32 LLDir_Win32::countFilesInDir(const std::string &dirname, const std::string &  	return (file_count);  } + +// get the next file in the directory +BOOL LLDir_Win32::getNextFileInDir(const std::string &dirname, const std::string &mask, std::string &fname) +{ +    BOOL fileFound = FALSE; +	fname = ""; + +	WIN32_FIND_DATAW FileData; +    llutf16string pathname = utf8str_to_utf16str(dirname) + utf8str_to_utf16str(mask); + +	if (pathname != mCurrentDir) +	{ +		// different dir specified, close old search +		if (mCurrentDir[0]) +		{ +			FindClose(mDirSearch_h); +		} +		mCurrentDir = pathname; + +		// and open new one +		// Check error opening Directory structure +		if ((mDirSearch_h = FindFirstFile(pathname.c_str(), &FileData)) != INVALID_HANDLE_VALUE)    +		{ +           fileFound = TRUE; +		} +	} + +    // Loop to skip over the current (.) and parent (..) directory entries +    // (apparently returned in Win7 but not XP) +    do +    { +       if (   fileFound +           && (  (lstrcmp(FileData.cFileName, (LPCTSTR)TEXT(".")) == 0) +               ||(lstrcmp(FileData.cFileName, (LPCTSTR)TEXT("..")) == 0) +               ) +           ) +       { +          fileFound = FALSE; +       } +    } while (   mDirSearch_h != INVALID_HANDLE_VALUE +             && !fileFound +             && (fileFound = FindNextFile(mDirSearch_h, &FileData) +                 ) +             ); + +    if (!fileFound && GetLastError() == ERROR_NO_MORE_FILES) +    { +       // No more files, so reset to beginning of directory +       FindClose(mDirSearch_h); +       mCurrentDir[0] = '\000'; +    } + +    if (fileFound) +    { +        // convert from TCHAR to char +        fname = utf16str_to_utf8str(FileData.cFileName); +	} +     +	return fileFound; +} +  std::string LLDir_Win32::getCurPath()  {  	WCHAR w_str[MAX_PATH]; diff --git a/indra/llvfs/lldir_win32.h b/indra/llvfs/lldir_win32.h index 19c610eb8b..4c932c932c 100644 --- a/indra/llvfs/lldir_win32.h +++ b/indra/llvfs/lldir_win32.h @@ -40,12 +40,15 @@ public:  	/*virtual*/ std::string getCurPath();  	/*virtual*/ U32 countFilesInDir(const std::string &dirname, const std::string &mask); +	/*virtual*/ BOOL getNextFileInDir(const std::string &dirname, const std::string &mask, std::string &fname);  	/*virtual*/ BOOL fileExists(const std::string &filename) const;  	/*virtual*/ std::string getLLPluginLauncher();  	/*virtual*/ std::string getLLPluginFilename(std::string base_name);  private: +	BOOL LLDir_Win32::getNextFileInDir(const llutf16string &dirname, const std::string &mask, std::string &fname); +	  	void* mDirSearch_h;  	llutf16string mCurrentDir;  }; diff --git a/indra/llvfs/lldiriterator.cpp b/indra/llvfs/lldiriterator.cpp deleted file mode 100644 index 5536ed8f69..0000000000 --- a/indra/llvfs/lldiriterator.cpp +++ /dev/null @@ -1,203 +0,0 @@ -/** - * @file lldiriterator.cpp - * @brief Iterator through directory entries matching the search pattern. - * - * $LicenseInfo:firstyear=2010&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA - * $/LicenseInfo$ - */ - -#include "lldiriterator.h" - -#include <boost/filesystem.hpp> -#include <boost/regex.hpp> - -namespace fs = boost::filesystem; - -static std::string glob_to_regex(const std::string& glob); - -class LLDirIterator::Impl -{ -public: -	Impl(const std::string &dirname, const std::string &mask); -	~Impl(); - -	bool next(std::string &fname); - -private: -	boost::regex			mFilterExp; -	fs::directory_iterator	mIter; -	bool					mIsValid; -}; - -LLDirIterator::Impl::Impl(const std::string &dirname, const std::string &mask) -	: mIsValid(false) -{ -	fs::path dir_path(dirname); - -	// Check if path exists. -	if (!fs::exists(dir_path)) -	{ -		llerrs << "Invalid path: \"" << dir_path.string() << "\"" << llendl; -		return; -	} - -	// Initialize the directory iterator for the given path. -	try -	{ -		mIter = fs::directory_iterator(dir_path); -	} -	catch (fs::basic_filesystem_error<fs::path>& e) -	{ -		llerrs << e.what() << llendl; -		return; -	} - -	// Convert the glob mask to a regular expression -	std::string exp = glob_to_regex(mask); - -	// Initialize boost::regex with the expression converted from -	// the glob mask. -	// An exception is thrown if the expression is not valid. -	try -	{ -		mFilterExp.assign(exp); -	} -	catch (boost::regex_error& e) -	{ -		llerrs << "\"" << exp << "\" is not a valid regular expression: " -				<< e.what() << llendl; -		return; -	} - -	mIsValid = true; -} - -LLDirIterator::Impl::~Impl() -{ -} - -bool LLDirIterator::Impl::next(std::string &fname) -{ -	fname = ""; - -	if (!mIsValid) -	{ -		llerrs << "The iterator is not correctly initialized." << llendl; -		return false; -	} - -	fs::directory_iterator end_itr; // default construction yields past-the-end -	bool found = false; -	while (mIter != end_itr && !found) -	{ -		boost::smatch match; -		std::string name = mIter->path().filename(); -		if (found = boost::regex_match(name, match, mFilterExp)) -		{ -			fname = name; -		} - -		++mIter; -	} - -	return found; -} - -std::string glob_to_regex(const std::string& glob) -{ -	std::string regex; -	regex.reserve(glob.size()<<1); -	S32 braces = 0; -	bool escaped = false; -	bool square_brace_open = false; - -	for (std::string::const_iterator i = glob.begin(); i != glob.end(); ++i) -	{ -		char c = *i; - -		switch (c) -		{ -			case '.': -				regex+="\\."; -				break; -			case '*': -				if (glob.begin() == i) -				{ -					regex+="[^.].*"; -				} -				else -				{ -					regex+= escaped ? "*" : ".*"; -				} -				break; -			case '?': -				regex+= escaped ? '?' : '.'; -				break; -			case '{': -				braces++; -				regex+='('; -				break; -			case '}': -				if (!braces) -				{ -					llerrs << "glob_to_regex: Closing brace without an equivalent opening brace: " << glob << llendl; -				} - -				regex+=')'; -				braces--; -				break; -			case ',': -				regex+= braces ? '|' : c; -				break; -			case '!': -				regex+= square_brace_open ? '^' : c; -				break; -			default: -				regex+=c; -				break; -		} - -		escaped = ('\\' == c); -		square_brace_open = ('[' == c); -	} - -	if (braces) -	{ -		llerrs << "glob_to_regex: Unterminated brace expression: " << glob << llendl; -	} - -	return regex; -} - -LLDirIterator::LLDirIterator(const std::string &dirname, const std::string &mask) -{ -	mImpl = new Impl(dirname, mask); -} - -LLDirIterator::~LLDirIterator() -{ -	delete mImpl; -} - -bool LLDirIterator::next(std::string &fname) -{ -	return mImpl->next(fname); -} diff --git a/indra/llvfs/lldiriterator.h b/indra/llvfs/lldiriterator.h deleted file mode 100644 index 0b48be41b3..0000000000 --- a/indra/llvfs/lldiriterator.h +++ /dev/null @@ -1,87 +0,0 @@ -/** - * @file lldiriterator.h - * @brief Iterator through directory entries matching the search pattern. - * - * $LicenseInfo:firstyear=2010&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA - * $/LicenseInfo$ - */ - -#ifndef LL_LLDIRITERATOR_H -#define LL_LLDIRITERATOR_H - -#include "linden_common.h" - -/** - * Class LLDirIterator - * - * Iterates through directory entries matching the search pattern. - */ -class LLDirIterator -{ -public: -	/** -	 * Constructs LLDirIterator object to search for glob pattern -	 * matches in a directory. -	 * -	 * @param dirname - name of a directory to search in. -	 * @param mask - search pattern, a glob expression -	 * -	 * Wildcards supported in glob expressions: -	 * -------------------------------------------------------------- -	 * | Wildcard 	| Matches										| -	 * -------------------------------------------------------------- -	 * | 	* 		|zero or more characters						| -	 * | 	?		|exactly one character							| -	 * | [abcde]	|exactly one character listed					| -	 * | [a-e]		|exactly one character in the given range		| -	 * | [!abcde]	|any character that is not listed				| -	 * | [!a-e]		|any character that is not in the given range	| -	 * | {abc,xyz}	|exactly one entire word in the options given	| -	 * -------------------------------------------------------------- -	 */ -	LLDirIterator(const std::string &dirname, const std::string &mask); - -	~LLDirIterator(); - -	/** -	 * Searches for the next directory entry matching the glob mask -	 * specified upon iterator construction. -	 * Returns true if a match is found, sets fname -	 * parameter to the name of the matched directory entry and -	 * increments the iterator position. -	 * -	 * Typical usage: -	 * <code> -	 * LLDirIterator iter(directory, pattern); -	 * if ( iter.next(scanResult) ) -	 * </code> -	 * -	 * @param fname - name of the matched directory entry. -	 * @return true if a match is found, false otherwise. -	 */ -	bool next(std::string &fname); - -protected: -	class Impl; -	Impl* mImpl; -}; - -#endif //LL_LLDIRITERATOR_H diff --git a/indra/llvfs/tests/lldir_test.cpp b/indra/llvfs/tests/lldir_test.cpp index ea321c5ae9..8788bd63e8 100644 --- a/indra/llvfs/tests/lldir_test.cpp +++ b/indra/llvfs/tests/lldir_test.cpp @@ -28,7 +28,6 @@  #include "linden_common.h"  #include "../lldir.h" -#include "../lldiriterator.h"  #include "../test/lltut.h" @@ -260,12 +259,13 @@ namespace tut     std::string makeTestFile( const std::string& dir, const std::string& file )     { -      std::string path = dir + file; +      std::string delim = gDirUtilp->getDirDelimiter(); +      std::string path = dir + delim + file;        LLFILE* handle = LLFile::fopen( path, "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." -      ensure("failed to write to test file '"+path+"'", EOF != fputs("test file", handle) ); +      ensure("failed to write to test file '"+path+"'", fputs("test file", handle) >= 0);        fclose(handle);        return path;     } @@ -290,7 +290,7 @@ namespace tut     }     static const char* DirScanFilename[5] = { "file1.abc", "file2.abc", "file1.xyz", "file2.xyz", "file1.mno" }; - +        void scanTest(const std::string& directory, const std::string& pattern, bool correctResult[5])     { @@ -300,8 +300,7 @@ namespace tut        bool  filesFound[5] = { false, false, false, false, false };        //std::cerr << "searching '"+directory+"' for '"+pattern+"'\n"; -      LLDirIterator iter(directory, pattern); -      while ( found <= 5 && iter.next(scanResult) ) +      while ( found <= 5 && gDirUtilp->getNextFileInDir(directory, pattern, scanResult) )        {           found++;           //std::cerr << "  found '"+scanResult+"'\n"; @@ -335,15 +334,15 @@ namespace tut     template<> template<>     void LLDirTest_object_t::test<5>() -      // LLDirIterator::next +      // getNextFileInDir     {        std::string delim = gDirUtilp->getDirDelimiter();        std::string dirTemp = LLFile::tmpdir();        // 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(dirTemp + "getNextFileInDir"); +      std::string dir2 = makeTestDir(dirTemp + "getNextFileInDir");        std::string dir1files[5];        std::string dir2files[5];        for (int i=0; i<5; i++) @@ -381,17 +380,19 @@ namespace tut        scanTest(dir2, "file?.x?z", expected7);        // Scan dir2 and see if any file?.??c files are found -      bool  expected8[5] = { true, true, false, false, false }; -      scanTest(dir2, "file?.??c", expected8); -      scanTest(dir2, "*.??c", expected8); +      // THESE FAIL ON Mac and Windows, SO ARE COMMENTED OUT FOR NOW +      //      bool  expected8[5] = { true, true, false, false, false }; +      //      scanTest(dir2, "file?.??c", expected8); +      //      scanTest(dir2, "*.??c", expected8);        // Scan dir1 and see if any *.?n? files are found        bool  expected9[5] = { false, false, false, false, true };        scanTest(dir1, "*.?n?", expected9);        // Scan dir1 and see if any *.???? files are found -      bool  expected10[5] = { false, false, false, false, false }; -      scanTest(dir1, "*.????", expected10); +      // THIS ONE FAILS ON WINDOWS (returns three charater suffixes) SO IS COMMENTED OUT FOR NOW +      // bool  expected10[5] = { false, false, false, false, false }; +      // scanTest(dir1, "*.????", expected10);        // Scan dir1 and see if any ?????.* files are found        bool  expected11[5] = { true, true, true, true, true }; @@ -401,15 +402,6 @@ namespace tut        bool  expected12[5] = { false, false, true, true, false };        scanTest(dir1, "??l??.xyz", expected12); -      bool expected13[5] = { true, false, true, false, false }; -      scanTest(dir1, "file1.{abc,xyz}", expected13); - -      bool expected14[5] = { true, true, false, false, false }; -      scanTest(dir1, "file[0-9].abc", expected14); - -      bool expected15[5] = { true, true, false, false, false }; -      scanTest(dir1, "file[!a-z].abc", expected15); -        // clean up all test files and directories        for (int i=0; i<5; i++)        { diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 8ea0dd1089..437be15150 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -542,6 +542,7 @@ set(viewer_SOURCE_FILES      llviewerregion.cpp      llviewershadermgr.cpp      llviewerstats.cpp +    llviewerstatsrecorder.cpp      llviewertexteditor.cpp      llviewertexture.cpp      llviewertextureanim.cpp @@ -1081,6 +1082,7 @@ set(viewer_HEADER_FILES      llviewerregion.h      llviewershadermgr.h      llviewerstats.h +    llviewerstatsrecorder.h      llviewertexteditor.h      llviewertexture.h      llviewertextureanim.h diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 8193945f62..7e8c68632d 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -44,6 +44,7 @@  #include "llagentwearables.h"  #include "llwindow.h"  #include "llviewerstats.h" +#include "llviewerstatsrecorder.h"  #include "llmd5.h"  #include "llmeshrepository.h"  #include "llpumpio.h" @@ -92,7 +93,6 @@  // Linden library includes  #include "llavatarnamecache.h" -#include "lldiriterator.h"  #include "llimagej2c.h"  #include "llmemory.h"  #include "llprimitive.h" @@ -672,6 +672,10 @@ bool LLAppViewer::init()      mAlloc.setProfilingEnabled(gSavedSettings.getBOOL("MemProfiling")); +#if LL_RECORD_VIEWER_STATS +	LLViewerStatsRecorder::initClass(); +#endif +      // *NOTE:Mani - LLCurl::initClass is not thread safe.       // Called before threads are created.      LLCurl::initClass(); @@ -995,6 +999,8 @@ bool LLAppViewer::init()  	LLAgentLanguage::init(); + +  	return true;  } @@ -1736,6 +1742,10 @@ bool LLAppViewer::cleanup()  	LLMetricPerformanceTesterBasic::cleanClass() ; +#if LL_RECORD_VIEWER_STATS +	LLViewerStatsRecorder::cleanupClass(); +#endif +  	llinfos << "Cleaning up Media and Textures" << llendflush;  	//Note: @@ -3326,9 +3336,7 @@ void LLAppViewer::migrateCacheDirectory()  			S32 file_count = 0;  			std::string file_name;  			std::string mask = delimiter + "*.*"; - -			LLDirIterator iter(old_cache_dir, mask); -			while (iter.next(file_name)) +			while (gDirUtilp->getNextFileInDir(old_cache_dir, mask, file_name))  			{  				if (file_name == "." || file_name == "..") continue;  				std::string source_path = old_cache_dir + delimiter + file_name; @@ -3547,8 +3555,7 @@ bool LLAppViewer::initCache()  		dir = gDirUtilp->getExpandedFilename(LL_PATH_CACHE,"");  		std::string found_file; -		LLDirIterator iter(dir, mask); -		if (iter.next(found_file)) +		if (gDirUtilp->getNextFileInDir(dir, mask, found_file))  		{  			old_vfs_data_file = dir + gDirUtilp->getDirDelimiter() + found_file; diff --git a/indra/newview/llappviewerlinux.cpp b/indra/newview/llappviewerlinux.cpp index fc7a27e5e0..898cc1c0ba 100644 --- a/indra/newview/llappviewerlinux.cpp +++ b/indra/newview/llappviewerlinux.cpp @@ -30,7 +30,6 @@  #include "llcommandlineparser.h" -#include "lldiriterator.h"  #include "llmemtype.h"  #include "llurldispatcher.h"		// SLURL from other app instance  #include "llviewernetwork.h" @@ -505,9 +504,7 @@ std::string LLAppViewerLinux::generateSerialNumber()  	// trawl /dev/disk/by-uuid looking for a good-looking UUID to grab  	std::string this_name; - -	LLDirIterator iter(uuiddir, "*"); -	while (iter.next(this_name)) +	while (gDirUtilp->getNextFileInDir(uuiddir, "*", this_name))  	{  		if (this_name.length() > best.length() ||  		    (this_name.length() == best.length() && diff --git a/indra/newview/llfloateruipreview.cpp b/indra/newview/llfloateruipreview.cpp index 182d3d23f1..11b3379814 100644 --- a/indra/newview/llfloateruipreview.cpp +++ b/indra/newview/llfloateruipreview.cpp @@ -35,7 +35,6 @@  #include "llfloateruipreview.h"			// Own header  // Internal utility -#include "lldiriterator.h"  #include "lleventtimer.h"  #include "llexternaleditor.h"  #include "llrender.h" @@ -482,11 +481,9 @@ BOOL LLFloaterUIPreview::postBuild()  	std::string language_directory;  	std::string xui_dir = get_xui_dir();	// directory containing localizations -- don't forget trailing delim  	mLanguageSelection->removeall();																				// clear out anything temporarily in list from XML - -	LLDirIterator iter(xui_dir, "*");  	while(found)																									// for every directory  	{ -		if((found = iter.next(language_directory)))							// get next directory +		if((found = gDirUtilp->getNextFileInDir(xui_dir, "*", language_directory)))							// get next directory  		{  			std::string full_path = xui_dir + language_directory;  			if(LLFile::isfile(full_path.c_str()))																	// if it's not a directory, skip it @@ -638,51 +635,42 @@ void LLFloaterUIPreview::refreshList()  	mFileList->clearRows();		// empty list  	std::string name;  	BOOL found = TRUE; - -	LLDirIterator floater_iter(getLocalizedDirectory(), "floater_*.xml");  	while(found)				// for every floater file that matches the pattern  	{ -		if((found = floater_iter.next(name)))	// get next file matching pattern +		if((found = gDirUtilp->getNextFileInDir(getLocalizedDirectory(), "floater_*.xml", name)))	// get next file matching pattern  		{  			addFloaterEntry(name.c_str());	// and add it to the list (file name only; localization code takes care of rest of path)  		}  	}  	found = TRUE; - -	LLDirIterator inspect_iter(getLocalizedDirectory(), "inspect_*.xml");  	while(found)				// for every inspector file that matches the pattern  	{ -		if((found = inspect_iter.next(name)))	// get next file matching pattern +		if((found = gDirUtilp->getNextFileInDir(getLocalizedDirectory(), "inspect_*.xml", name)))	// get next file matching pattern  		{  			addFloaterEntry(name.c_str());	// and add it to the list (file name only; localization code takes care of rest of path)  		}  	}  	found = TRUE; - -	LLDirIterator menu_iter(getLocalizedDirectory(), "menu_*.xml");  	while(found)				// for every menu file that matches the pattern  	{ -		if((found = menu_iter.next(name)))	// get next file matching pattern +		if((found = gDirUtilp->getNextFileInDir(getLocalizedDirectory(), "menu_*.xml", name)))	// get next file matching pattern  		{  			addFloaterEntry(name.c_str());	// and add it to the list (file name only; localization code takes care of rest of path)  		}  	}  	found = TRUE; - -	LLDirIterator panel_iter(getLocalizedDirectory(), "panel_*.xml");  	while(found)				// for every panel file that matches the pattern  	{ -		if((found = panel_iter.next(name)))	// get next file matching pattern +		if((found = gDirUtilp->getNextFileInDir(getLocalizedDirectory(), "panel_*.xml", name)))	// get next file matching pattern  		{  			addFloaterEntry(name.c_str());	// and add it to the list (file name only; localization code takes care of rest of path)  		}  	} -	found = TRUE; -	LLDirIterator sidepanel_iter(getLocalizedDirectory(), "sidepanel_*.xml"); +	found = TRUE;  	while(found)				// for every sidepanel file that matches the pattern  	{ -		if((found = sidepanel_iter.next(name)))	// get next file matching pattern +		if((found = gDirUtilp->getNextFileInDir(getLocalizedDirectory(), "sidepanel_*.xml", name)))	// get next file matching pattern  		{  			addFloaterEntry(name.c_str());	// and add it to the list (file name only; localization code takes care of rest of path)  		} diff --git a/indra/newview/llinventorymodelbackgroundfetch.cpp b/indra/newview/llinventorymodelbackgroundfetch.cpp index eab8f187a7..570e48d526 100644 --- a/indra/newview/llinventorymodelbackgroundfetch.cpp +++ b/indra/newview/llinventorymodelbackgroundfetch.cpp @@ -181,7 +181,7 @@ void LLInventoryModelBackgroundFetch::backgroundFetch()  	if (mBackgroundFetchActive && gAgent.getRegion())  	{  		// If we'll be using the capability, we'll be sending batches and the background thing isn't as important. -		std::string url = gAgent.getRegion()->getCapability("WebFetchInventoryDescendents");    +		std::string url = gAgent.getRegion()->getCapability("FetchInventoryDescendents2");     		if (!url.empty())   		{  			bulkFetch(url); @@ -604,7 +604,7 @@ void LLInventoryModelBackgroundFetch::bulkFetch(std::string url)  		}  		if (body_lib["folders"].size())  		{ -			std::string url_lib = gAgent.getRegion()->getCapability("FetchLibDescendents"); +			std::string url_lib = gAgent.getRegion()->getCapability("FetchLibDescendents2");  			LLInventoryModelFetchDescendentsResponder *fetcher = new LLInventoryModelFetchDescendentsResponder(body_lib, recursive_cats);  			LLHTTPClient::post(url_lib, body_lib, fetcher, 300.0); diff --git a/indra/newview/llinventoryobserver.cpp b/indra/newview/llinventoryobserver.cpp index 91ff8c7867..0fd4b2bee5 100644 --- a/indra/newview/llinventoryobserver.cpp +++ b/indra/newview/llinventoryobserver.cpp @@ -203,8 +203,8 @@ void fetch_items_from_llsd(const LLSD& items_llsd)  {  	if (!items_llsd.size() || gDisconnected) return;  	LLSD body; -	body[0]["cap_name"] = "FetchInventory"; -	body[1]["cap_name"] = "FetchLib"; +	body[0]["cap_name"] = "FetchInventory2"; +	body[1]["cap_name"] = "FetchLib2";  	for (S32 i=0; i<items_llsd.size();i++)  	{  		if (items_llsd[i]["owner_id"].asString() == gAgent.getID().asString()) diff --git a/indra/newview/lllogchat.cpp b/indra/newview/lllogchat.cpp index b09cfbe907..9adf374c71 100644 --- a/indra/newview/lllogchat.cpp +++ b/indra/newview/lllogchat.cpp @@ -32,7 +32,6 @@  #include "lltrans.h"  #include "llviewercontrol.h" -#include "lldiriterator.h"  #include "llinstantmessage.h"  #include "llsingleton.h" // for LLSingleton @@ -602,8 +601,7 @@ std::string LLLogChat::oldLogFileName(std::string filename)  	//LL_INFOS("") << "Checking:" << directory << " for " << pattern << LL_ENDL;/* uncomment if you want to verify step, delete on commit */  	std::vector<std::string> allfiles; -	LLDirIterator iter(directory, pattern); -	while (iter.next(scanResult)) +    while (gDirUtilp->getNextFileInDir(directory, pattern, scanResult))      {  		//LL_INFOS("") << "Found   :" << scanResult << LL_ENDL;          allfiles.push_back(scanResult); diff --git a/indra/newview/llspatialpartition.cpp b/indra/newview/llspatialpartition.cpp index 1b5800b8a5..efda39c806 100644 --- a/indra/newview/llspatialpartition.cpp +++ b/indra/newview/llspatialpartition.cpp @@ -2671,6 +2671,49 @@ void renderCrossHairs(LLVector3 position, F32 size, LLColor4 color)  	gGL.end();  } +void renderUpdateType(LLDrawable* drawablep) +{ +	LLViewerObject* vobj = drawablep->getVObj(); +	if (!vobj || OUT_UNKNOWN == vobj->getLastUpdateType()) +	{ +		return; +	} +	LLGLEnable blend(GL_BLEND); +	switch (vobj->getLastUpdateType()) +	{ +	case OUT_FULL: +		glColor4f(0,1,0,0.5f); +		break; +	case OUT_TERSE_IMPROVED: +		glColor4f(0,1,1,0.5f); +		break; +	case OUT_FULL_COMPRESSED: +		if (vobj->getLastUpdateCached()) +		{ +			glColor4f(1,0,0,0.5f); +		} +		else +		{ +			glColor4f(1,1,0,0.5f); +		} +		break; +	case OUT_FULL_CACHED: +		glColor4f(0,0,1,0.5f); +		break; +	default: +		llwarns << "Unknown update_type " << vobj->getLastUpdateType() << llendl; +		break; +	}; +	S32 num_faces = drawablep->getNumFaces(); +	if (num_faces) +	{ +		for (S32 i = 0; i < num_faces; ++i) +		{ +			pushVerts(drawablep->getFace(i), LLVertexBuffer::MAP_VERTEX); +		} +	} +} +  void renderBoundingBox(LLDrawable* drawable, BOOL set_color = TRUE)  { @@ -3774,6 +3817,10 @@ public:  			{  				renderRaycast(drawable);  			} +			if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_UPDATE_TYPE)) +			{ +				renderUpdateType(drawable); +			}  			LLVOAvatar* avatar = dynamic_cast<LLVOAvatar*>(drawable->getVObj().get()); @@ -3990,6 +4037,7 @@ void LLSpatialPartition::renderDebug()  									  LLPipeline::RENDER_DEBUG_OCCLUSION |  									  LLPipeline::RENDER_DEBUG_LIGHTS |  									  LLPipeline::RENDER_DEBUG_BATCH_SIZE | +									  LLPipeline::RENDER_DEBUG_UPDATE_TYPE |  									  LLPipeline::RENDER_DEBUG_BBOXES |  									  LLPipeline::RENDER_DEBUG_NORMALS |  									  LLPipeline::RENDER_DEBUG_POINTS | diff --git a/indra/newview/llviewerinventory.cpp b/indra/newview/llviewerinventory.cpp index b3642a2c1e..cc851e676b 100644 --- a/indra/newview/llviewerinventory.cpp +++ b/indra/newview/llviewerinventory.cpp @@ -366,11 +366,11 @@ void LLViewerInventoryItem::fetchFromServer(void) const  		{  		  if(gAgent.getID() != mPermissions.getOwner())  		    { -		      url = region->getCapability("FetchLib"); +		      url = region->getCapability("FetchLib2");  		    }  		  else  		    {	 -		      url = region->getCapability("FetchInventory"); +		      url = region->getCapability("FetchInventory2");  		    }  		}  		else @@ -648,7 +648,7 @@ bool LLViewerInventoryCategory::fetch()  		std::string url;  		if (gAgent.getRegion())  		{ -			url = gAgent.getRegion()->getCapability("WebFetchInventoryDescendents"); +			url = gAgent.getRegion()->getCapability("FetchInventoryDescendents2");  		}  		else  		{ @@ -660,7 +660,7 @@ bool LLViewerInventoryCategory::fetch()  		}  		else  		{	//Deprecated, but if we don't have a capability, use the old system. -			llinfos << "WebFetchInventoryDescendents capability not found.  Using deprecated UDP message." << llendl; +			llinfos << "FetchInventoryDescendents2 capability not found.  Using deprecated UDP message." << llendl;  			LLMessageSystem* msg = gMessageSystem;  			msg->newMessage("FetchInventoryDescendents");  			msg->nextBlock("AgentData"); diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp index d78eef70bd..cd72e69055 100644 --- a/indra/newview/llviewermedia.cpp +++ b/indra/newview/llviewermedia.cpp @@ -54,7 +54,6 @@  #include "llfilepicker.h"  #include "llnotifications.h" -#include "lldiriterator.h"  #include "llevent.h"		// LLSimpleListener  #include "llnotificationsutil.h"  #include "lluuid.h" @@ -1116,8 +1115,7 @@ void LLViewerMedia::clearAllCookies()  	}  	// the hard part: iterate over all user directories and delete the cookie file from each one -	LLDirIterator dir_iter(base_dir, "*_*"); -	while (dir_iter.next(filename)) +	while(gDirUtilp->getNextFileInDir(base_dir, "*_*", filename))  	{  		target = base_dir;  		target += filename; diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index 0f980986d3..a152ab4aa0 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -913,6 +913,10 @@ U32 info_display_from_string(std::string info_display)  	{  		return LLPipeline::RENDER_DEBUG_BATCH_SIZE;  	} +	else if ("update type" == info_display) +	{ +		return LLPipeline::RENDER_DEBUG_UPDATE_TYPE; +	}  	else if ("texture anim" == info_display)  	{  		return LLPipeline::RENDER_DEBUG_TEXTURE_ANIM; diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp index 27f371df9c..f380d4b183 100644 --- a/indra/newview/llviewerobject.cpp +++ b/indra/newview/llviewerobject.cpp @@ -241,13 +241,12 @@ LLViewerObject::LLViewerObject(const LLUUID &id, const LLPCode pcode, LLViewerRe  	mState(0),  	mMedia(NULL),  	mClickAction(0), -	mObjectCost(0.f), -	mLinksetCost(0.f), -	mPhysicsCost(0.f),  	mLinksetPhysicsCost(0.f),  	mCostStale(true),  	mPhysicsShapeUnknown(true), -	mAttachmentItemID(LLUUID::null) +	mAttachmentItemID(LLUUID::null), +	mLastUpdateType(OUT_UNKNOWN), +	mLastUpdateCached(FALSE)  {  	if (!is_global)  	{ @@ -5617,6 +5616,15 @@ const LLUUID &LLViewerObject::extractAttachmentItemID()  	return getAttachmentItemID();  } +EObjectUpdateType LLViewerObject::getLastUpdateType() const +{ +	return mLastUpdateType; +} + +void LLViewerObject::setLastUpdateType(EObjectUpdateType last_update_type) +{ +	mLastUpdateType = last_update_type; +}  //virtual  LLVOAvatar* LLViewerObject::getAvatar() const diff --git a/indra/newview/llviewerobject.h b/indra/newview/llviewerobject.h index 0b6d8483e9..8883272cde 100644 --- a/indra/newview/llviewerobject.h +++ b/indra/newview/llviewerobject.h @@ -77,6 +77,7 @@ typedef enum e_object_update_type  	OUT_TERSE_IMPROVED,  	OUT_FULL_COMPRESSED,  	OUT_FULL_CACHED, +	OUT_UNKNOWN,  } EObjectUpdateType; @@ -743,8 +744,15 @@ public:  	const LLUUID &getAttachmentItemID() const;  	void setAttachmentItemID(const LLUUID &id);  	const LLUUID &extractAttachmentItemID(); // find&set the inventory item ID of the attached object +	EObjectUpdateType getLastUpdateType() const; +	void setLastUpdateType(EObjectUpdateType last_update_type); +	BOOL getLastUpdateCached() const; +	void setLastUpdateCached(BOOL last_update_cached); +  private:  	LLUUID mAttachmentItemID; // ItemID of the associated object is in user inventory. +	EObjectUpdateType	mLastUpdateType; +	BOOL	mLastUpdateCached;  };  /////////////////// diff --git a/indra/newview/llviewerobjectlist.cpp b/indra/newview/llviewerobjectlist.cpp index 7682d71e7f..e2dd4d075c 100644 --- a/indra/newview/llviewerobjectlist.cpp +++ b/indra/newview/llviewerobjectlist.cpp @@ -57,6 +57,7 @@  #include "llsdutil.h"  #include "llviewerregion.h"  #include "llviewerstats.h" +#include "llviewerstatsrecorder.h"  #include "llvoavatarself.h"  #include "lltoolmgr.h"  #include "lltoolpie.h" @@ -303,8 +304,10 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys,  	// have to transform to absolute coordinates.  	num_objects = mesgsys->getNumberOfBlocksFast(_PREHASH_ObjectData); +	// I don't think this case is ever hit.  TODO* Test this.  	if (!cached && !compressed && update_type != OUT_FULL)  	{ +		//llinfos << "TEST: !cached && !compressed && update_type != OUT_FULL" << llendl;  		gTerseObjectUpdates += num_objects;  		S32 size;  		if (mesgsys->getReceiveCompressedSize()) @@ -315,7 +318,7 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys,  		{  			size = mesgsys->getReceiveSize();  		} -		// llinfos << "Received terse " << num_objects << " in " << size << " byte (" << size/num_objects << ")" << llendl; +		//llinfos << "Received terse " << num_objects << " in " << size << " byte (" << size/num_objects << ")" << llendl;  	}  	else  	{ @@ -346,9 +349,14 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys,  	U8 compressed_dpbuffer[2048];  	LLDataPackerBinaryBuffer compressed_dp(compressed_dpbuffer, 2048);  	LLDataPacker *cached_dpp = NULL; -	 + +#if LL_RECORD_VIEWER_STATS +	LLViewerStatsRecorder::instance()->beginObjectUpdateEvents(regionp); +#endif +  	for (i = 0; i < num_objects; i++)  	{ +		// timer is unused?  		LLTimer update_timer;  		BOOL justCreated = FALSE; @@ -360,9 +368,11 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys,  			mesgsys->getU32Fast(_PREHASH_ObjectData, _PREHASH_CRC, crc, i);  			// Lookup data packer and add this id to cache miss lists if necessary. -			cached_dpp = regionp->getDP(id, crc); +			U8 cache_miss_type = LLViewerRegion::CACHE_MISS_TYPE_NONE; +			cached_dpp = regionp->getDP(id, crc, cache_miss_type);  			if (cached_dpp)  			{ +				// Cache Hit.  				cached_dpp->reset();  				cached_dpp->unpackUUID(fullid, "ID");  				cached_dpp->unpackU32(local_id, "LocalID"); @@ -370,6 +380,11 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys,  			}  			else  			{ +				// Cache Miss. +				#if LL_RECORD_VIEWER_STATS +				LLViewerStatsRecorder::instance()->recordCacheMissEvent(id, update_type, cache_miss_type); +				#endif +  				continue; // no data packer, skip this object  			}  		} @@ -381,13 +396,15 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys,  			compressed_dp.reset();  			U32 flags = 0; -			if (update_type != OUT_TERSE_IMPROVED) +			if (update_type != OUT_TERSE_IMPROVED) // OUT_FULL_COMPRESSED only?  			{  				mesgsys->getU32Fast(_PREHASH_ObjectData, _PREHASH_UpdateFlags, flags, i);  			} +			// I don't think we ever use this flag from the server.  DK 2010/12/09  			if (flags & FLAGS_ZLIB_COMPRESSED)  			{ +				//llinfos << "TEST: flags & FLAGS_ZLIB_COMPRESSED" << llendl;  				compressed_length = mesgsys->getSizeFast(_PREHASH_ObjectData, i, _PREHASH_Data);  				mesgsys->getBinaryDataFast(_PREHASH_ObjectData, _PREHASH_Data, compbuffer, 0, i);  				uncompressed_length = 2048; @@ -403,7 +420,7 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys,  			} -			if (update_type != OUT_TERSE_IMPROVED) +			if (update_type != OUT_TERSE_IMPROVED) // OUT_FULL_COMPRESSED only?  			{  				compressed_dp.unpackUUID(fullid, "ID");  				compressed_dp.unpackU32(local_id, "LocalID"); @@ -423,7 +440,7 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys,  				}  			}  		} -		else if (update_type != OUT_FULL) +		else if (update_type != OUT_FULL) // !compressed, !OUT_FULL ==> OUT_FULL_CACHED only?  		{  			mesgsys->getU32Fast(_PREHASH_ObjectData, _PREHASH_ID, local_id, i);  			getUUIDFromLocal(fullid, @@ -436,7 +453,7 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys,  				mNumUnknownUpdates++;  			}  		} -		else +		else // OUT_FULL only?  		{  			mesgsys->getUUIDFast(_PREHASH_ObjectData, _PREHASH_FullID, fullid, i);  			mesgsys->getU32Fast(_PREHASH_ObjectData, _PREHASH_ID, local_id, i); @@ -468,12 +485,12 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys,  							gMessageSystem->getSenderPort());  			if (objectp->mLocalID != local_id) -			{    // Update local ID in object with the one sent from the region +			{	// Update local ID in object with the one sent from the region  				objectp->mLocalID = local_id;  			}  			if (objectp->getRegion() != regionp) -			{    // Object changed region, so update it +			{	// Object changed region, so update it  				objectp->updateRegion(regionp); // for LLVOAvatar  			}  		} @@ -484,18 +501,24 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys,  			{  				if (update_type == OUT_TERSE_IMPROVED)  				{ -					// llinfos << "terse update for an unknown object:" << fullid << llendl; +					// llinfos << "terse update for an unknown object (compressed):" << fullid << llendl; +					#if LL_RECORD_VIEWER_STATS +					LLViewerStatsRecorder::instance()->recordObjectUpdateFailure(local_id, update_type); +					#endif  					continue;  				}  			} -			else if (cached) +			else if (cached) // Cache hit only?  			{  			}  			else  			{  				if (update_type != OUT_FULL)  				{ -					// llinfos << "terse update for an unknown object:" << fullid << llendl; +					//llinfos << "terse update for an unknown object:" << fullid << llendl; +					#if LL_RECORD_VIEWER_STATS +					LLViewerStatsRecorder::instance()->recordObjectUpdateFailure(local_id, update_type); +					#endif  					continue;  				} @@ -505,7 +528,10 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys,  			if (mDeadObjects.find(fullid) != mDeadObjects.end())  			{  				mNumDeadObjectUpdates++; -				// llinfos << "update for a dead object:" << fullid << llendl; +				//llinfos << "update for a dead object:" << fullid << llendl; +				#if LL_RECORD_VIEWER_STATS +				LLViewerStatsRecorder::instance()->recordObjectUpdateFailure(local_id, update_type); +				#endif  				continue;  			}  #endif @@ -513,6 +539,10 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys,  			objectp = createObject(pcode, regionp, fullid, local_id, gMessageSystem->getSender());  			if (!objectp)  			{ +				llinfos << "createObject failure for object: " << fullid << llendl; +				#if LL_RECORD_VIEWER_STATS +				LLViewerStatsRecorder::instance()->recordObjectUpdateFailure(local_id, update_type); +				#endif  				continue;  			}  			justCreated = TRUE; @@ -525,19 +555,26 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys,  			llwarns << "Dead object " << objectp->mID << " in UUID map 1!" << llendl;  		} +		bool bCached = false;  		if (compressed)  		{ -			if (update_type != OUT_TERSE_IMPROVED) +			if (update_type != OUT_TERSE_IMPROVED) // OUT_FULL_COMPRESSED only?  			{  				objectp->mLocalID = local_id;  			}  			processUpdateCore(objectp, user_data, i, update_type, &compressed_dp, justCreated); -			if (update_type != OUT_TERSE_IMPROVED) +			if (update_type != OUT_TERSE_IMPROVED) // OUT_FULL_COMPRESSED only?  			{ +				bCached = true; +				#if LL_RECORD_VIEWER_STATS +				LLViewerRegion::eCacheUpdateResult result = objectp->mRegionp->cacheFullUpdate(objectp, compressed_dp); +				LLViewerStatsRecorder::instance()->recordCacheFullUpdate(local_id, update_type, result, objectp); +				#else  				objectp->mRegionp->cacheFullUpdate(objectp, compressed_dp); +				#endif  			}  		} -		else if (cached) +		else if (cached) // Cache hit only?  		{  			objectp->mLocalID = local_id;  			processUpdateCore(objectp, user_data, i, update_type, cached_dpp, justCreated); @@ -550,8 +587,17 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys,  			}  			processUpdateCore(objectp, user_data, i, update_type, NULL, justCreated);  		} +		#if LL_RECORD_VIEWER_STATS +		LLViewerStatsRecorder::instance()->recordObjectUpdateEvent(local_id, update_type, objectp); +		#endif +		objectp->setLastUpdateType(update_type); +		objectp->setLastUpdateCached(bCached);  	} +#if LL_RECORD_VIEWER_STATS +	LLViewerStatsRecorder::instance()->endObjectUpdateEvents(); +#endif +  	LLVOAvatar::cullAvatarsByPixelArea();  } @@ -865,12 +911,12 @@ void LLViewerObjectList::update(LLAgent &agent, LLWorld &world)  	// update global timer  	F32 last_time = gFrameTimeSeconds; -	U64 time = totalTime();                 // this will become the new gFrameTime when the update is done +	U64 time = totalTime();				 // this will become the new gFrameTime when the update is done  	// Time _can_ go backwards, for example if the user changes the system clock.  	// It doesn't cause any fatal problems (just some oddness with stats), so we shouldn't assert here.  //	llassert(time > gFrameTime);  	F64 time_diff = U64_to_F64(time - gFrameTime)/(F64)SEC_TO_MICROSEC; -	gFrameTime    = time; +	gFrameTime	= time;  	F64 time_since_start = U64_to_F64(gFrameTime - gStartTime)/(F64)SEC_TO_MICROSEC;  	gFrameTimeSeconds = (F32)time_since_start; @@ -975,7 +1021,7 @@ void LLViewerObjectList::update(LLAgent &agent, LLWorld &world)  		{  			std::string id_str;  			objectp->mID.toString(id_str); -			std::string tmpstr = std::string("Par:    ") + id_str; +			std::string tmpstr = std::string("Par:	") + id_str;  			addDebugBeacon(objectp->getPositionAgent(),  							tmpstr,  							LLColor4(1.f,0.f,0.f,1.f), @@ -995,12 +1041,12 @@ void LLViewerObjectList::update(LLAgent &agent, LLWorld &world)  			std::string tmpstr;  			if (objectp->getParent())  			{ -				tmpstr = std::string("ChP:    ") + id_str; +				tmpstr = std::string("ChP:	") + id_str;  				text_color = LLColor4(0.f, 1.f, 0.f, 1.f);  			}  			else  			{ -				tmpstr = std::string("ChNoP:    ") + id_str; +				tmpstr = std::string("ChNoP:	") + id_str;  				text_color = LLColor4(1.f, 0.f, 0.f, 1.f);  			}  			id = sIndexAndLocalIDToUUID[oi.mParentInfo]; @@ -1885,8 +1931,8 @@ void LLViewerObjectList::findOrphans(LLViewerObject* objectp, U32 ip, U32 port)  			llinfos << "Agent: " << objectp->getPositionAgent() << llendl;  			addDebugBeacon(objectp->getPositionAgent(),"");  #endif -            gPipeline.markMoved(objectp->mDrawable);                 -            objectp->setChanged(LLXform::MOVED | LLXform::SILHOUETTE); +			gPipeline.markMoved(objectp->mDrawable);				 +			objectp->setChanged(LLXform::MOVED | LLXform::SILHOUETTE);  			// Flag the object as no longer orphaned  			childp->mOrphaned = FALSE; diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp index 16aa9069fd..7fd6979702 100644 --- a/indra/newview/llviewerregion.cpp +++ b/indra/newview/llviewerregion.cpp @@ -59,6 +59,7 @@  #include "llurldispatcher.h"  #include "llviewerobjectlist.h"  #include "llviewerparceloverlay.h" +#include "llviewerstatsrecorder.h"  #include "llvlmanager.h"  #include "llvlcomposition.h"  #include "llvocache.h" @@ -1032,7 +1033,7 @@ void LLViewerRegion::getInfo(LLSD& info)  	info["Region"]["Handle"]["y"] = (LLSD::Integer)y;  } -void LLViewerRegion::cacheFullUpdate(LLViewerObject* objectp, LLDataPackerBinaryBuffer &dp) +LLViewerRegion::eCacheUpdateResult LLViewerRegion::cacheFullUpdate(LLViewerObject* objectp, LLDataPackerBinaryBuffer &dp)  {  	U32 local_id = objectp->getLocalID();  	U32 crc = objectp->getCRC(); @@ -1046,35 +1047,36 @@ void LLViewerRegion::cacheFullUpdate(LLViewerObject* objectp, LLDataPackerBinary  		{  			// Record a hit  			entry->recordDupe(); +			return CACHE_UPDATE_DUPE;  		} -		else -		{ -			// Update the cache entry -			mCacheMap.erase(local_id); -			delete entry; -			entry = new LLVOCacheEntry(local_id, crc, dp); -			mCacheMap[local_id] = entry; -		} -	} -	else -	{ -		// we haven't seen this object before -		// Create new entry and add to map -		if (mCacheMap.size() > MAX_OBJECT_CACHE_ENTRIES) -		{ -			mCacheMap.erase(mCacheMap.begin()); -		} +		// Update the cache entry +		mCacheMap.erase(local_id); +		delete entry;  		entry = new LLVOCacheEntry(local_id, crc, dp); -  		mCacheMap[local_id] = entry; +		return CACHE_UPDATE_CHANGED;  	} -	return ; + +	// we haven't seen this object before + +	// Create new entry and add to map +	eCacheUpdateResult result = CACHE_UPDATE_ADDED; +	if (mCacheMap.size() > MAX_OBJECT_CACHE_ENTRIES) +	{ +		mCacheMap.erase(mCacheMap.begin()); +		result = CACHE_UPDATE_REPLACED; +		 +	} +	entry = new LLVOCacheEntry(local_id, crc, dp); + +	mCacheMap[local_id] = entry; +	return result;  }  // Get data packer for this object, if we have cached data  // AND the CRC matches. JC -LLDataPacker *LLViewerRegion::getDP(U32 local_id, U32 crc) +LLDataPacker *LLViewerRegion::getDP(U32 local_id, U32 crc, U8 &cache_miss_type)  {  	//llassert(mCacheLoaded);  This assert failes often, changing to early-out -- davep, 2010/10/18 @@ -1089,17 +1091,20 @@ LLDataPacker *LLViewerRegion::getDP(U32 local_id, U32 crc)  			{  				// Record a hit  				entry->recordHit(); +			cache_miss_type = CACHE_MISS_TYPE_NONE;  				return entry->getDP(crc);  			}  			else  			{  				// llinfos << "CRC miss for " << local_id << llendl; +			cache_miss_type = CACHE_MISS_TYPE_CRC;  				mCacheMissCRC.put(local_id);  			}  		}  		else  		{  			// llinfos << "Cache miss for " << local_id << llendl; +		cache_miss_type = CACHE_MISS_TYPE_FULL;  			mCacheMissFull.put(local_id);  		}  	} @@ -1122,9 +1127,6 @@ void LLViewerRegion::requestCacheMisses()  	S32 blocks = 0;  	S32 i; -	const U8 CACHE_MISS_TYPE_FULL = 0; -	const U8 CACHE_MISS_TYPE_CRC  = 1; -  	// Send full cache miss updates.  For these, we KNOW we don't  	// have a viewer object.  	for (i = 0; i < full_count; i++) @@ -1187,6 +1189,11 @@ void LLViewerRegion::requestCacheMisses()  	mCacheDirty = TRUE ;  	// llinfos << "KILLDEBUG Sent cache miss full " << full_count << " crc " << crc_count << llendl; +	#if LL_RECORD_VIEWER_STATS +	LLViewerStatsRecorder::instance()->beginObjectUpdateEvents(this); +	LLViewerStatsRecorder::instance()->recordRequestCacheMissesEvent(full_count + crc_count); +	LLViewerStatsRecorder::instance()->endObjectUpdateEvents(); +	#endif  }  void LLViewerRegion::dumpCache() @@ -1375,11 +1382,12 @@ void LLViewerRegion::setSeedCapability(const std::string& url)  	capabilityNames.append("DispatchRegionInfo");  	capabilityNames.append("EstateChangeInfo");  	capabilityNames.append("EventQueueGet"); -	capabilityNames.append("FetchInventory");  	capabilityNames.append("ObjectMedia");  	capabilityNames.append("ObjectMediaNavigate"); -	capabilityNames.append("FetchLib"); -	capabilityNames.append("FetchLibDescendents"); +	capabilityNames.append("FetchLib2"); +	capabilityNames.append("FetchLibDescendents2"); +	capabilityNames.append("FetchInventory2"); +	capabilityNames.append("FetchInventoryDescendents2");  	capabilityNames.append("GetDisplayNames");  	capabilityNames.append("GetTexture");  	capabilityNames.append("GetMesh"); @@ -1427,7 +1435,6 @@ void LLViewerRegion::setSeedCapability(const std::string& url)  	capabilityNames.append("ViewerMetrics");  	capabilityNames.append("ViewerStartAuction");  	capabilityNames.append("ViewerStats"); -	capabilityNames.append("WebFetchInventoryDescendents");  	// Please add new capabilities alphabetically to reduce  	// merge conflicts. diff --git a/indra/newview/llviewerregion.h b/indra/newview/llviewerregion.h index 3d3f1d62a6..7c6559203e 100644 --- a/indra/newview/llviewerregion.h +++ b/indra/newview/llviewerregion.h @@ -51,7 +51,7 @@  // Surface id's  #define LAND  1  #define WATER 2 -const U32	MAX_OBJECT_CACHE_ENTRIES = 10000; +const U32	MAX_OBJECT_CACHE_ENTRIES = 50000;  class LLEventPoll; @@ -275,9 +275,24 @@ public:  	void getInfo(LLSD& info); +	typedef enum +	{ +		CACHE_MISS_TYPE_FULL = 0, +		CACHE_MISS_TYPE_CRC, +		CACHE_MISS_TYPE_NONE +	} eCacheMissType; + +	typedef enum +	{ +		CACHE_UPDATE_DUPE = 0, +		CACHE_UPDATE_CHANGED, +		CACHE_UPDATE_ADDED, +		CACHE_UPDATE_REPLACED +	} eCacheUpdateResult; +  	// handle a full update message -	void cacheFullUpdate(LLViewerObject* objectp, LLDataPackerBinaryBuffer &dp); -	LLDataPacker *getDP(U32 local_id, U32 crc); +	eCacheUpdateResult cacheFullUpdate(LLViewerObject* objectp, LLDataPackerBinaryBuffer &dp); +	LLDataPacker *getDP(U32 local_id, U32 crc, U8 &cache_miss_type);  	void requestCacheMisses();  	void addCacheMissFull(const U32 local_id); diff --git a/indra/newview/llviewerstatsrecorder.cpp b/indra/newview/llviewerstatsrecorder.cpp new file mode 100644 index 0000000000..e9d21b4848 --- /dev/null +++ b/indra/newview/llviewerstatsrecorder.cpp @@ -0,0 +1,258 @@ +/** + * @file llviewerstatsrecorder.cpp + * @brief record info about viewer events to a metrics log file + * + * $LicenseInfo:firstyear=2010&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + *  + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + *  + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + *  + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA + *  + * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" +#include "llviewerstatsrecorder.h" + +#if LL_RECORD_VIEWER_STATS + +#include "llfile.h" +#include "llviewerregion.h" +#include "llviewerobject.h" + + +// To do - something using region name or global position +#if LL_WINDOWS +	static const std::string STATS_FILE_NAME("C:\\ViewerObjectCacheStats.csv"); +#else +	static const std::string STATS_FILE_NAME("/tmp/viewerstats.csv"); +#endif + +LLViewerStatsRecorder* LLViewerStatsRecorder::sInstance = NULL; +LLViewerStatsRecorder::LLViewerStatsRecorder() : +	mObjectCacheFile(NULL), +	mTimer(), +	mRegionp(NULL), +	mStartTime(0.f), +	mProcessingTime(0.f) +{ +	if (NULL != sInstance) +	{ +		llerrs << "Attempted to create multiple instances of LLViewerStatsRecorder!" << llendl; +	} +	sInstance = this; +	clearStats(); +} + +LLViewerStatsRecorder::~LLViewerStatsRecorder() +{ +	if (mObjectCacheFile != NULL) +	{ +		LLFile::close(mObjectCacheFile); +		mObjectCacheFile = NULL; +	} +} + +// static +void LLViewerStatsRecorder::initClass() +{ +	sInstance = new LLViewerStatsRecorder(); +} + +// static +void LLViewerStatsRecorder::cleanupClass() +{ +	delete sInstance; +	sInstance = NULL; +} + + +void LLViewerStatsRecorder::initStatsRecorder(LLViewerRegion *regionp) +{ +	if (mObjectCacheFile == NULL) +	{ +		mStartTime = LLTimer::getTotalTime(); +		mObjectCacheFile = LLFile::fopen(STATS_FILE_NAME, "wb"); +		if (mObjectCacheFile) +		{	// Write column headers +			std::ostringstream data_msg; +			data_msg << "EventTime, " +				<< "ProcessingTime, " +				<< "CacheHits, " +				<< "CacheFullMisses, " +				<< "CacheCrcMisses, " +				<< "FullUpdates, " +				<< "TerseUpdates, " +				<< "CacheMissRequests, " +				<< "CacheMissResponses, " +				<< "CacheUpdateDupes, " +				<< "CacheUpdateChanges, " +				<< "CacheUpdateAdds, " +				<< "CacheUpdateReplacements, " +				<< "UpdateFailures" +				<< "\n"; + +			fwrite(data_msg.str().c_str(), 1, data_msg.str().size(), mObjectCacheFile ); +		} +	} +} + +void LLViewerStatsRecorder::beginObjectUpdateEvents(LLViewerRegion *regionp) +{ +	initStatsRecorder(regionp); +	mRegionp = regionp; +	mProcessingTime = LLTimer::getTotalTime(); +	clearStats(); +} + +void LLViewerStatsRecorder::clearStats() +{ +	mObjectCacheHitCount = 0; +	mObjectCacheMissFullCount = 0; +	mObjectCacheMissCrcCount = 0; +	mObjectFullUpdates = 0; +	mObjectTerseUpdates = 0; +	mObjectCacheMissRequests = 0; +	mObjectCacheMissResponses = 0; +	mObjectCacheUpdateDupes = 0; +	mObjectCacheUpdateChanges = 0; +	mObjectCacheUpdateAdds = 0; +	mObjectCacheUpdateReplacements = 0; +	mObjectUpdateFailures = 0; +} + + +void LLViewerStatsRecorder::recordObjectUpdateFailure(U32 local_id, const EObjectUpdateType update_type) +{ +	mObjectUpdateFailures++; +} + +void LLViewerStatsRecorder::recordCacheMissEvent(U32 local_id, const EObjectUpdateType update_type, U8 cache_miss_type) +{ +	if (LLViewerRegion::CACHE_MISS_TYPE_FULL == cache_miss_type) +	{ +		mObjectCacheMissFullCount++; +	} +	else +	{ +		mObjectCacheMissCrcCount++; +	} +} + +void LLViewerStatsRecorder::recordObjectUpdateEvent(U32 local_id, const EObjectUpdateType update_type, LLViewerObject * objectp) +{ +	switch (update_type) +	{ +	case OUT_FULL: +		mObjectFullUpdates++; +		break; +	case OUT_TERSE_IMPROVED: +		mObjectTerseUpdates++; +		break; +	case OUT_FULL_COMPRESSED: +		mObjectCacheMissResponses++; +		break; +	case OUT_FULL_CACHED: +		mObjectCacheHitCount++; +		break; +	default: +		llwarns << "Unknown update_type" << llendl; +		break; +	}; +} + +void LLViewerStatsRecorder::recordCacheFullUpdate(U32 local_id, const EObjectUpdateType update_type, LLViewerRegion::eCacheUpdateResult update_result, LLViewerObject* objectp) +{ +	switch (update_result) +	{ +		case LLViewerRegion::CACHE_UPDATE_DUPE: +			mObjectCacheUpdateDupes++; +			break; +		case LLViewerRegion::CACHE_UPDATE_CHANGED: +			mObjectCacheUpdateChanges++; +			break; +		case LLViewerRegion::CACHE_UPDATE_ADDED: +			mObjectCacheUpdateAdds++; +			break; +		case LLViewerRegion::CACHE_UPDATE_REPLACED: +			mObjectCacheUpdateReplacements++; +			break; +		default: +			llwarns << "Unknown update_result type" << llendl; +			break; +	}; +} + +void LLViewerStatsRecorder::recordRequestCacheMissesEvent(S32 count) +{ +	mObjectCacheMissRequests += count; +} + +void LLViewerStatsRecorder::endObjectUpdateEvents() +{ +	llinfos << "ILX: "  +		<< mObjectCacheHitCount << " hits, "  +		<< mObjectCacheMissFullCount << " full misses, " +		<< mObjectCacheMissCrcCount << " crc misses, " +		<< mObjectFullUpdates << " full updates, " +		<< mObjectTerseUpdates << " terse updates, " +		<< mObjectCacheMissRequests << " cache miss requests, " +		<< mObjectCacheMissResponses << " cache miss responses, " +		<< mObjectCacheUpdateDupes << " cache update dupes, " +		<< mObjectCacheUpdateChanges << " cache update changes, " +		<< mObjectCacheUpdateAdds << " cache update adds, " +		<< mObjectCacheUpdateReplacements << " cache update replacements, " +		<< mObjectUpdateFailures << " update failures" +		<< llendl; + +	S32 total_objects = mObjectCacheHitCount + mObjectCacheMissCrcCount + mObjectCacheMissFullCount + mObjectFullUpdates + mObjectTerseUpdates + mObjectCacheMissRequests + mObjectCacheMissResponses + mObjectCacheUpdateDupes + mObjectCacheUpdateChanges + mObjectCacheUpdateAdds + mObjectCacheUpdateReplacements + mObjectUpdateFailures; +	if (mObjectCacheFile != NULL && +		total_objects > 0) +	{ +		std::ostringstream data_msg; +		F32 processing32 = (F32) ((LLTimer::getTotalTime() - mProcessingTime) / 1000.0); + +		data_msg << getTimeSinceStart() +			<< ", " << processing32 +			<< ", " << mObjectCacheHitCount +			<< ", " << mObjectCacheMissFullCount +			<< ", " << mObjectCacheMissCrcCount +			<< ", " << mObjectFullUpdates +			<< ", " << mObjectTerseUpdates +			<< ", " << mObjectCacheMissRequests +			<< ", " << mObjectCacheMissResponses +			<< ", " << mObjectCacheUpdateDupes +			<< ", " << mObjectCacheUpdateChanges +			<< ", " << mObjectCacheUpdateAdds +			<< ", " << mObjectCacheUpdateReplacements +			<< ", " << mObjectUpdateFailures +			<< "\n"; + +		fwrite(data_msg.str().c_str(), 1, data_msg.str().size(), mObjectCacheFile ); +	} + +	clearStats(); +} + +F32 LLViewerStatsRecorder::getTimeSinceStart() +{ +	return (F32) ((LLTimer::getTotalTime() - mStartTime) / 1000.0); +} + +#endif + + + diff --git a/indra/newview/llviewerstatsrecorder.h b/indra/newview/llviewerstatsrecorder.h new file mode 100644 index 0000000000..612ac380f7 --- /dev/null +++ b/indra/newview/llviewerstatsrecorder.h @@ -0,0 +1,97 @@ +/** + * @file llviewerstatsrecorder.h + * @brief record info about viewer events to a metrics log file + * + * $LicenseInfo:firstyear=2010&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + *  + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + *  + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + *  + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA + *  + * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA + * $/LicenseInfo$ + */ + +#ifndef LLVIEWERSTATSRECORDER_H +#define LLVIEWERSTATSRECORDER_H + + +// This is a diagnostic class used to record information from the viewer +// for analysis. + +// This is normally 0.  Set to 1 to enable viewer stats recording +#define LL_RECORD_VIEWER_STATS	0 + + +#if LL_RECORD_VIEWER_STATS +#include "llframetimer.h" +#include "llviewerobject.h" +#include "llviewerregion.h" + +class LLMutex; +class LLViewerRegion; +class LLViewerObject; + +class LLViewerStatsRecorder +{ + public: +	LLViewerStatsRecorder(); +	~LLViewerStatsRecorder(); + +	static void initClass(); +	static void cleanupClass(); +	static LLViewerStatsRecorder* instance() {return sInstance; } + +	void initStatsRecorder(LLViewerRegion *regionp); + +	void beginObjectUpdateEvents(LLViewerRegion *regionp); +	void recordObjectUpdateFailure(U32 local_id, const EObjectUpdateType update_type); +	void recordCacheMissEvent(U32 local_id, const EObjectUpdateType update_type, U8 cache_miss_type); +	void recordObjectUpdateEvent(U32 local_id, const EObjectUpdateType update_type, LLViewerObject * objectp); +	void recordCacheFullUpdate(U32 local_id, const EObjectUpdateType update_type, LLViewerRegion::eCacheUpdateResult update_result, LLViewerObject* objectp); +	void recordRequestCacheMissesEvent(S32 count); +	void endObjectUpdateEvents(); + +	F32 getTimeSinceStart(); + +private: +	static LLViewerStatsRecorder* sInstance; + +	LLFILE *	mObjectCacheFile;		// File to write data into +	LLFrameTimer	mTimer; +	LLViewerRegion*	mRegionp; +	F64			mStartTime; +	F64			mProcessingTime; + +	S32			mObjectCacheHitCount; +	S32			mObjectCacheMissFullCount; +	S32			mObjectCacheMissCrcCount; +	S32			mObjectFullUpdates; +	S32			mObjectTerseUpdates; +	S32			mObjectCacheMissRequests; +	S32			mObjectCacheMissResponses; +	S32			mObjectCacheUpdateDupes; +	S32			mObjectCacheUpdateChanges; +	S32			mObjectCacheUpdateAdds; +	S32			mObjectCacheUpdateReplacements; +	S32			mObjectUpdateFailures; + + +	void	clearStats(); +}; +#endif	// LL_RECORD_VIEWER_STATS + +#endif // LLVIEWERSTATSRECORDER_H + diff --git a/indra/newview/llvocache.cpp b/indra/newview/llvocache.cpp index 6ea88abab8..2188b41a06 100644 --- a/indra/newview/llvocache.cpp +++ b/indra/newview/llvocache.cpp @@ -1,707 +1,720 @@ -/**  - * @file llvocache.cpp - * @brief Cache of objects on the viewer. - * - * $LicenseInfo:firstyear=2003&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - *  - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - *  - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU - * Lesser General Public License for more details. - *  - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA - *  - * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA - * $/LicenseInfo$ - */ - -#include "llviewerprecompiledheaders.h" -#include "llvocache.h" -#include "llerror.h" -#include "llregionhandle.h" -#include "llviewercontrol.h" - -BOOL check_read(LLAPRFile* apr_file, void* src, S32 n_bytes)  -{ -	return apr_file->read(src, n_bytes) == n_bytes ; -} - -BOOL check_write(LLAPRFile* apr_file, void* src, S32 n_bytes)  -{ -	return apr_file->write(src, n_bytes) == n_bytes ; -} - - -//--------------------------------------------------------------------------- -// LLVOCacheEntry -//--------------------------------------------------------------------------- - -LLVOCacheEntry::LLVOCacheEntry(U32 local_id, U32 crc, LLDataPackerBinaryBuffer &dp) -	: -	mLocalID(local_id), -	mCRC(crc), -	mHitCount(0), -	mDupeCount(0), -	mCRCChangeCount(0) -{ -	mBuffer = new U8[dp.getBufferSize()]; -	mDP.assignBuffer(mBuffer, dp.getBufferSize()); -	mDP = dp; -} - -LLVOCacheEntry::LLVOCacheEntry() -	: -	mLocalID(0), -	mCRC(0), -	mHitCount(0), -	mDupeCount(0), -	mCRCChangeCount(0), -	mBuffer(NULL) -{ -	mDP.assignBuffer(mBuffer, 0); -} - -LLVOCacheEntry::LLVOCacheEntry(LLAPRFile* apr_file) -{ -	S32 size = -1; -	BOOL success; - -	success = check_read(apr_file, &mLocalID, sizeof(U32)); -	if(success) -	{ -		success = check_read(apr_file, &mCRC, sizeof(U32)); -	} -	if(success) -	{ -		success = check_read(apr_file, &mHitCount, sizeof(S32)); -	} -	if(success) -	{ -		success = check_read(apr_file, &mDupeCount, sizeof(S32)); -	} -	if(success) -	{ -		success = check_read(apr_file, &mCRCChangeCount, sizeof(S32)); -	} -	if(success) -	{ -		success = check_read(apr_file, &size, sizeof(S32)); - -		// Corruption in the cache entries -		if ((size > 10000) || (size < 1)) -		{ -			// We've got a bogus size, skip reading it. -			// We won't bother seeking, because the rest of this file -			// is likely bogus, and will be tossed anyway. -			llwarns << "Bogus cache entry, size " << size << ", aborting!" << llendl; -			success = FALSE; -		} -	} -	if(success && size > 0) -	{ -		mBuffer = new U8[size]; -		success = check_read(apr_file, mBuffer, size); - -		if(success) -		{ -			mDP.assignBuffer(mBuffer, size); -		} -		else -		{ -			delete[] mBuffer ; -			mBuffer = NULL ; -		} -	} - -	if(!success) -	{ -		mLocalID = 0; -		mCRC = 0; -		mHitCount = 0; -		mDupeCount = 0; -		mCRCChangeCount = 0; -		mBuffer = NULL; -	} -} - -LLVOCacheEntry::~LLVOCacheEntry() -{ -	delete [] mBuffer; -} - - -// New CRC means the object has changed. -void LLVOCacheEntry::assignCRC(U32 crc, LLDataPackerBinaryBuffer &dp) -{ -	if (  (mCRC != crc) -		||(mDP.getBufferSize() == 0)) -	{ -		mCRC = crc; -		mHitCount = 0; -		mCRCChangeCount++; - -		mDP.freeBuffer(); -		mBuffer = new U8[dp.getBufferSize()]; -		mDP.assignBuffer(mBuffer, dp.getBufferSize()); -		mDP = dp; -	} -} - -LLDataPackerBinaryBuffer *LLVOCacheEntry::getDP(U32 crc) -{ -	if (  (mCRC != crc) -		||(mDP.getBufferSize() == 0)) -	{ -		//llinfos << "Not getting cache entry, invalid!" << llendl; -		return NULL; -	} -	mHitCount++; -	return &mDP; -} - - -void LLVOCacheEntry::recordHit() -{ -	mHitCount++; -} - - -void LLVOCacheEntry::dump() const -{ -	llinfos << "local " << mLocalID -		<< " crc " << mCRC -		<< " hits " << mHitCount -		<< " dupes " << mDupeCount -		<< " change " << mCRCChangeCount -		<< llendl; -} - -BOOL LLVOCacheEntry::writeToFile(LLAPRFile* apr_file) const -{ -	BOOL success; -	success = check_write(apr_file, (void*)&mLocalID, sizeof(U32)); -	if(success) -	{ -		success = check_write(apr_file, (void*)&mCRC, sizeof(U32)); -	} -	if(success) -	{ -		success = check_write(apr_file, (void*)&mHitCount, sizeof(S32)); -	} -	if(success) -	{ -		success = check_write(apr_file, (void*)&mDupeCount, sizeof(S32)); -	} -	if(success) -	{ -		success = check_write(apr_file, (void*)&mCRCChangeCount, sizeof(S32)); -	} -	if(success) -	{ -		S32 size = mDP.getBufferSize(); -		success = check_write(apr_file, (void*)&size, sizeof(S32)); -	 -		if(success) -		{ -			success = check_write(apr_file, (void*)mBuffer, size); -		} -	} - -	return success ; -} - -//------------------------------------------------------------------- -//LLVOCache -//------------------------------------------------------------------- -// Format string used to construct filename for the object cache -static const char OBJECT_CACHE_FILENAME[] = "objects_%d_%d.slc"; - -const U32 NUM_ENTRIES_TO_PURGE = 50; -const char* object_cache_dirname = "objectcache"; -const char* header_filename = "object.cache"; - -LLVOCache* LLVOCache::sInstance = NULL; - -//static  -LLVOCache* LLVOCache::getInstance()  -{	 -	if(!sInstance) -	{ -		sInstance = new LLVOCache() ; -	} -	return sInstance ; -} - -//static  -BOOL LLVOCache::hasInstance()  -{ -	return sInstance != NULL ; -} - -//static  -void LLVOCache::destroyClass()  -{ -	if(sInstance) -	{ -		delete sInstance ; -		sInstance = NULL ; -	} -} - -LLVOCache::LLVOCache(): -	mInitialized(FALSE), -	mReadOnly(TRUE), -	mCacheSize(1) -{ -	mEnabled = gSavedSettings.getBOOL("ObjectCacheEnabled"); -	mLocalAPRFilePoolp = new LLVolatileAPRPool() ; -} - -LLVOCache::~LLVOCache() -{ -	if(mEnabled) -	{ -		writeCacheHeader(); -		clearCacheInMemory(); -	} -	delete mLocalAPRFilePoolp; -} - -void LLVOCache::setDirNames(ELLPath location) -{ -	std::string delem = gDirUtilp->getDirDelimiter(); - -	mHeaderFileName = gDirUtilp->getExpandedFilename(location, object_cache_dirname, header_filename); -	mObjectCacheDirName = gDirUtilp->getExpandedFilename(location, object_cache_dirname); -} - -void LLVOCache::initCache(ELLPath location, U32 size, U32 cache_version) -{ -	if(!mEnabled) -	{ -		llwarns << "Not initializing cache: Cache is currently disabled." << llendl; -		return ; -	} - -	if(mInitialized) -	{ -		llwarns << "Cache already initialized." << llendl; -		return ; -	} - -	setDirNames(location); -	if (!mReadOnly) -	{ -		LLFile::mkdir(mObjectCacheDirName); -	} - -	mCacheSize = size; - -	mMetaInfo.mVersion = cache_version; -	readCacheHeader(); -	mInitialized = TRUE ; - -	if(mMetaInfo.mVersion != cache_version)  -	{ -		mMetaInfo.mVersion = cache_version ; -		if(mReadOnly) //disable cache -		{ -			clearCacheInMemory(); -		} -		else //delete the current cache if the format does not match. -		{			 -			removeCache(); -		} -	}	 -} -	 -void LLVOCache::removeCache(ELLPath location)  -{ -	if(mReadOnly) -	{ -		llwarns << "Not removing cache at " << location << ": Cache is currently in read-only mode." << llendl; -		return ; -	} - -	std::string delem = gDirUtilp->getDirDelimiter(); -	std::string mask = delem + "*"; -	std::string cache_dir = gDirUtilp->getExpandedFilename(location, object_cache_dirname); -	gDirUtilp->deleteFilesInDir(cache_dir, mask); //delete all files -	LLFile::rmdir(cache_dir); - -	clearCacheInMemory(); -	mInitialized = FALSE ; -} - -void LLVOCache::removeCache()  -{ -	llassert_always(mInitialized) ; -	if(mReadOnly) -	{ -		llwarns << "Not clearing object cache: Cache is currently in read-only mode." << llendl; -		return ; -	} - -	std::string delem = gDirUtilp->getDirDelimiter(); -	std::string mask = delem + "*"; -	gDirUtilp->deleteFilesInDir(mObjectCacheDirName, mask);  - -	clearCacheInMemory() ; -	writeCacheHeader(); -} - -void LLVOCache::clearCacheInMemory() -{ -	std::for_each(mHandleEntryMap.begin(), mHandleEntryMap.end(), DeletePairedPointer()); -	mHandleEntryMap.clear(); -} - -void LLVOCache::getObjectCacheFilename(U64 handle, std::string& filename)  -{ -	U32 region_x, region_y; - -	grid_from_region_handle(handle, ®ion_x, ®ion_y); -	filename = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, object_cache_dirname, -			   llformat(OBJECT_CACHE_FILENAME, region_x, region_y)); - -	return ; -} - -void LLVOCache::removeFromCache(U64 handle) -{ -	if(mReadOnly) -	{ -		llwarns << "Not removing cache for handle " << handle << ": Cache is currently in read-only mode." << llendl; -		return ; -	} - -	std::string filename; -	getObjectCacheFilename(handle, filename); -	LLAPRFile::remove(filename, mLocalAPRFilePoolp);	 -} - -BOOL LLVOCache::checkRead(LLAPRFile* apr_file, void* src, S32 n_bytes)  -{ -	if(!check_read(apr_file, src, n_bytes)) -	{ -		removeCache() ; -		return FALSE ; -	} - -	return TRUE ; -} - -BOOL LLVOCache::checkWrite(LLAPRFile* apr_file, void* src, S32 n_bytes)  -{ -	if(!check_write(apr_file, src, n_bytes)) -	{ -		removeCache() ; -		return FALSE ; -	} - -	return TRUE ; -} - -void LLVOCache::readCacheHeader() -{ -	if(!mEnabled) -	{ -		llwarns << "Not reading cache header: Cache is currently disabled." << llendl; -		return; -	} - -	//clear stale info. -	clearCacheInMemory();	 - -	if (LLAPRFile::isExist(mHeaderFileName, mLocalAPRFilePoolp)) -	{ -		LLAPRFile* apr_file = new LLAPRFile(mHeaderFileName, APR_READ|APR_BINARY, mLocalAPRFilePoolp);		 -		 -		//read the meta element -		if(!checkRead(apr_file, &mMetaInfo, sizeof(HeaderMetaInfo))) -		{ -			llwarns << "Error reading meta information from cache header." << llendl; -			delete apr_file; -			return; -		} - -		HeaderEntryInfo* entry ; -		for(U32 entry_index = 0; entry_index < mCacheSize; ++entry_index) -		{ -			entry = new HeaderEntryInfo() ; -			if(!checkRead(apr_file, entry, sizeof(HeaderEntryInfo))) -			{ -				llwarns << "Error reading cache header entry. (entry_index=" << entry_index << ")" << llendl; -				delete entry ;			 -				break; -			} -			else if(!entry->mTime) //end of the cache. -			{ -				delete entry ; -				break; -			} - -			entry->mIndex = entry_index; -			mHandleEntryMap[entry->mHandle] = entry; -		} - -		delete apr_file ; -	} -	else -	{ -		writeCacheHeader() ; -	} -} - -void LLVOCache::writeCacheHeader() -{ -	if (!mEnabled) -	{ -		llwarns << "Not writing cache header: Cache is currently disabled." << llendl; -		return; -	} - -	if(mReadOnly) -	{ -		llwarns << "Not writing cache header: Cache is currently in read-only mode." << llendl; -		return; -	} - -	LLAPRFile* apr_file = new LLAPRFile(mHeaderFileName, APR_CREATE|APR_WRITE|APR_BINARY, mLocalAPRFilePoolp); - -	//write the meta element -	if(!checkWrite(apr_file, &mMetaInfo, sizeof(HeaderMetaInfo))) -	{ -		llwarns << "Error writing meta information to cache header." << llendl; -		delete apr_file; -		return; -	} - -	U32 entry_index = 0; -	handle_entry_map_t::iterator iter_end = mHandleEntryMap.end(); -	for(handle_entry_map_t::iterator iter = mHandleEntryMap.begin(); -		iter != iter_end; -		++iter) -	{ -		HeaderEntryInfo* entry = iter->second; -		entry->mIndex = entry_index++; -		if(!checkWrite(apr_file, (void*)entry, sizeof(HeaderEntryInfo))) -		{ -			llwarns << "Failed to write cache header for entry " << entry->mHandle << " (entry_index = " << entry_index << ")" << llendl; -			delete apr_file; -			return; -		} -	} - -	// Why do we need to fill the cache header with default entries?  DK 2010-12-14 -	// It looks like we currently rely on the file being pre-allocated so we can seek during updateEntry(). -	if(entry_index < mCacheSize) -	{ -		HeaderEntryInfo* entry = new HeaderEntryInfo() ; -		for(; entry_index < mCacheSize; ++entry_index) -		{ -			//fill the cache with the default entry. -			if(!checkWrite(apr_file, entry, sizeof(HeaderEntryInfo))) -			{ -				llwarns << "Failed to fill cache header with default entries (entry_index = " << entry_index << ").  Switching to read-only mode." << llendl; -				mReadOnly = TRUE ; //disable the cache. -				break; -			} -		} -		delete entry ; -	} -	delete apr_file ; -} - -BOOL LLVOCache::updateEntry(const HeaderEntryInfo* entry) -{ -	LLAPRFile* apr_file = new LLAPRFile(mHeaderFileName, APR_WRITE|APR_BINARY, mLocalAPRFilePoolp); -	apr_file->seek(APR_SET, entry->mIndex * sizeof(HeaderEntryInfo) + sizeof(HeaderMetaInfo)) ; - -	BOOL result = checkWrite(apr_file, (void*)entry, sizeof(HeaderEntryInfo)) ; -	delete apr_file; -	return result; -} - -void LLVOCache::readFromCache(U64 handle, const LLUUID& id, LLVOCacheEntry::vocache_entry_map_t& cache_entry_map)  -{ -	if(!mEnabled) -	{ -		llwarns << "Not reading cache for handle " << handle << "): Cache is currently disabled." << llendl; -		return ; -	} -	llassert_always(mInitialized); - -	handle_entry_map_t::iterator iter = mHandleEntryMap.find(handle) ; -	if(iter == mHandleEntryMap.end()) //no cache -	{ -		llwarns << "No handle map entry for " << handle << llendl; -		return ; -	} - -	std::string filename; -	getObjectCacheFilename(handle, filename); -	LLAPRFile* apr_file = new LLAPRFile(filename, APR_READ|APR_BINARY, mLocalAPRFilePoolp); - -	LLUUID cache_id ; -	if(!checkRead(apr_file, cache_id.mData, UUID_BYTES)) -	{ -		llwarns << "Error reading cache_id from " << filename << llendl; -		delete apr_file; -		return ; -	} -	if(cache_id != id) -	{ -		llwarns << "Cache ID (" << cache_id << ") doesn't match id for this region (" << id << "), discarding.  handle = " << handle << llendl; -		delete apr_file ; -		return ; -	} - -	S32 num_entries; -	if(!checkRead(apr_file, &num_entries, sizeof(S32))) -	{ -		llwarns << "Error reading num_entries from " << filename << llendl; -		delete apr_file; -		return ; -	} -	 -	for (S32 i = 0; i < num_entries; i++) -	{ -		LLVOCacheEntry* entry = new LLVOCacheEntry(apr_file); -		if (!entry->getLocalID()) -		{ -			llwarns << "Aborting cache file load for " << filename << ", cache file corruption! (entry number = " << i << ")" << llendl; -			delete entry ; -			break; -		} -		cache_entry_map[entry->getLocalID()] = entry; -	} - -	delete apr_file ; -	return ; -} -	 -void LLVOCache::purgeEntries() -{ -	U32 limit = mCacheSize - NUM_ENTRIES_TO_PURGE ; -	// Construct a vector of entries out of the map so we can sort by time. -	std::vector<HeaderEntryInfo*> header_vector; -	handle_entry_map_t::iterator iter_end = mHandleEntryMap.end(); -	for (handle_entry_map_t::iterator iter = mHandleEntryMap.begin(); -		iter != iter_end; -		++iter) -	{ -		header_vector.push_back(iter->second); -	} -	// Sort by time, oldest first. -	std::sort(header_vector.begin(), header_vector.end(), header_entry_less()); -	while(header_vector.size() > limit) -	{ -		HeaderEntryInfo* entry = header_vector.front(); -		 -		removeFromCache(entry->mHandle); -		mHandleEntryMap.erase(entry->mHandle); -		header_vector.erase(header_vector.begin()); -		delete entry; -	} - -	writeCacheHeader() ; -	// *TODO: Verify that we can avoid re-reading the cache header.  DK 2010-12-14 -	readCacheHeader() ; -} - -void LLVOCache::writeToCache(U64 handle, const LLUUID& id, const LLVOCacheEntry::vocache_entry_map_t& cache_entry_map, BOOL dirty_cache)  -{ -	if(!mEnabled) -	{ -		llwarns << "Not writing cache for handle " << handle << "): Cache is currently disabled." << llendl; -		return ; -	} -	llassert_always(mInitialized); - -	if(mReadOnly) -	{ -		llwarns << "Not writing cache for handle " << handle << "): Cache is currently in read-only mode." << llendl; -		return ; -	} - -	HeaderEntryInfo* entry; -	handle_entry_map_t::iterator iter = mHandleEntryMap.find(handle) ; -	U32 num_handle_entries = mHandleEntryMap.size(); -	if(iter == mHandleEntryMap.end()) //new entry -	{ -		if(num_handle_entries >= mCacheSize) -		{ -			purgeEntries() ; -		} -		 -		entry = new HeaderEntryInfo(); -		entry->mHandle = handle ; -		entry->mTime = time(NULL) ; -		entry->mIndex = num_handle_entries++; -		mHandleEntryMap[handle] = entry ; -	} -	else -	{ -		// Update access time. -		entry = iter->second ; -		entry->mTime = time(NULL) ; -	} - -	//update cache header -	if(!updateEntry(entry)) -	{ -		llwarns << "Failed to update cache header index " << entry->mIndex << ". handle = " << handle << llendl; -		return ; //update failed. -	} - -	if(!dirty_cache) -	{ -		llwarns << "Skipping write to cache for handle " << handle << ": cache not dirty" << llendl; -		return ; //nothing changed, no need to update. -	} - -	//write to cache file -	std::string filename; -	getObjectCacheFilename(handle, filename); -	LLAPRFile* apr_file = new LLAPRFile(filename, APR_CREATE|APR_WRITE|APR_BINARY, mLocalAPRFilePoolp); -	 -	if(!checkWrite(apr_file, (void*)id.mData, UUID_BYTES)) -	{ -		llwarns << "Error writing id to " << filename << llendl; -		delete apr_file; -		return ; -	} - -	S32 num_entries = cache_entry_map.size() ; -	if(!checkWrite(apr_file, &num_entries, sizeof(S32))) -	{ -		llwarns << "Error writing num_entries to " << filename << llendl; -		delete apr_file; -		return ; -	} - -	for (LLVOCacheEntry::vocache_entry_map_t::const_iterator iter = cache_entry_map.begin(); iter != cache_entry_map.end(); ++iter) -	{ -		if(!iter->second->writeToFile(apr_file)) -		{ -			llwarns << "Aborting cache file write for " << filename << ", error writing to file!" << llendl; -			//failed -			removeCache() ; -			break; -		} -	} - -	delete apr_file ; -	return ; -} - +/** 
 + * @file llvocache.cpp
 + * @brief Cache of objects on the viewer.
 + *
 + * $LicenseInfo:firstyear=2003&license=viewerlgpl$
 + * Second Life Viewer Source Code
 + * Copyright (C) 2010, Linden Research, Inc.
 + * 
 + * This library is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation;
 + * version 2.1 of the License only.
 + * 
 + * This library is distributed in the hope that it will be useful,
 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 + * Lesser General Public License for more details.
 + * 
 + * You should have received a copy of the GNU Lesser General Public
 + * License along with this library; if not, write to the Free Software
 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 + * 
 + * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
 + * $/LicenseInfo$
 + */
 +
 +#include "llviewerprecompiledheaders.h"
 +#include "llvocache.h"
 +#include "llerror.h"
 +#include "llregionhandle.h"
 +#include "llviewercontrol.h"
 +
 +BOOL check_read(LLAPRFile* apr_file, void* src, S32 n_bytes) 
 +{
 +	return apr_file->read(src, n_bytes) == n_bytes ;
 +}
 +
 +BOOL check_write(LLAPRFile* apr_file, void* src, S32 n_bytes) 
 +{
 +	return apr_file->write(src, n_bytes) == n_bytes ;
 +}
 +
 +
 +//---------------------------------------------------------------------------
 +// LLVOCacheEntry
 +//---------------------------------------------------------------------------
 +
 +LLVOCacheEntry::LLVOCacheEntry(U32 local_id, U32 crc, LLDataPackerBinaryBuffer &dp)
 +	:
 +	mLocalID(local_id),
 +	mCRC(crc),
 +	mHitCount(0),
 +	mDupeCount(0),
 +	mCRCChangeCount(0)
 +{
 +	mBuffer = new U8[dp.getBufferSize()];
 +	mDP.assignBuffer(mBuffer, dp.getBufferSize());
 +	mDP = dp;
 +}
 +
 +LLVOCacheEntry::LLVOCacheEntry()
 +	:
 +	mLocalID(0),
 +	mCRC(0),
 +	mHitCount(0),
 +	mDupeCount(0),
 +	mCRCChangeCount(0),
 +	mBuffer(NULL)
 +{
 +	mDP.assignBuffer(mBuffer, 0);
 +}
 +
 +LLVOCacheEntry::LLVOCacheEntry(LLAPRFile* apr_file)
 +{
 +	S32 size = -1;
 +	BOOL success;
 +
 +	success = check_read(apr_file, &mLocalID, sizeof(U32));
 +	if(success)
 +	{
 +		success = check_read(apr_file, &mCRC, sizeof(U32));
 +	}
 +	if(success)
 +	{
 +		success = check_read(apr_file, &mHitCount, sizeof(S32));
 +	}
 +	if(success)
 +	{
 +		success = check_read(apr_file, &mDupeCount, sizeof(S32));
 +	}
 +	if(success)
 +	{
 +		success = check_read(apr_file, &mCRCChangeCount, sizeof(S32));
 +	}
 +	if(success)
 +	{
 +		success = check_read(apr_file, &size, sizeof(S32));
 +
 +		// Corruption in the cache entries
 +		if ((size > 10000) || (size < 1))
 +		{
 +			// We've got a bogus size, skip reading it.
 +			// We won't bother seeking, because the rest of this file
 +			// is likely bogus, and will be tossed anyway.
 +			llwarns << "Bogus cache entry, size " << size << ", aborting!" << llendl;
 +			success = FALSE;
 +		}
 +	}
 +	if(success && size > 0)
 +	{
 +		mBuffer = new U8[size];
 +		success = check_read(apr_file, mBuffer, size);
 +
 +		if(success)
 +		{
 +			mDP.assignBuffer(mBuffer, size);
 +		}
 +		else
 +		{
 +			delete[] mBuffer ;
 +			mBuffer = NULL ;
 +		}
 +	}
 +
 +	if(!success)
 +	{
 +		mLocalID = 0;
 +		mCRC = 0;
 +		mHitCount = 0;
 +		mDupeCount = 0;
 +		mCRCChangeCount = 0;
 +		mBuffer = NULL;
 +	}
 +}
 +
 +LLVOCacheEntry::~LLVOCacheEntry()
 +{
 +	delete [] mBuffer;
 +}
 +
 +
 +// New CRC means the object has changed.
 +void LLVOCacheEntry::assignCRC(U32 crc, LLDataPackerBinaryBuffer &dp)
 +{
 +	if (  (mCRC != crc)
 +		||(mDP.getBufferSize() == 0))
 +	{
 +		mCRC = crc;
 +		mHitCount = 0;
 +		mCRCChangeCount++;
 +
 +		mDP.freeBuffer();
 +		mBuffer = new U8[dp.getBufferSize()];
 +		mDP.assignBuffer(mBuffer, dp.getBufferSize());
 +		mDP = dp;
 +	}
 +}
 +
 +LLDataPackerBinaryBuffer *LLVOCacheEntry::getDP(U32 crc)
 +{
 +	if (  (mCRC != crc)
 +		||(mDP.getBufferSize() == 0))
 +	{
 +		//llinfos << "Not getting cache entry, invalid!" << llendl;
 +		return NULL;
 +	}
 +	mHitCount++;
 +	return &mDP;
 +}
 +
 +
 +void LLVOCacheEntry::recordHit()
 +{
 +	mHitCount++;
 +}
 +
 +
 +void LLVOCacheEntry::dump() const
 +{
 +	llinfos << "local " << mLocalID
 +		<< " crc " << mCRC
 +		<< " hits " << mHitCount
 +		<< " dupes " << mDupeCount
 +		<< " change " << mCRCChangeCount
 +		<< llendl;
 +}
 +
 +BOOL LLVOCacheEntry::writeToFile(LLAPRFile* apr_file) const
 +{
 +	BOOL success;
 +	success = check_write(apr_file, (void*)&mLocalID, sizeof(U32));
 +	if(success)
 +	{
 +		success = check_write(apr_file, (void*)&mCRC, sizeof(U32));
 +	}
 +	if(success)
 +	{
 +		success = check_write(apr_file, (void*)&mHitCount, sizeof(S32));
 +	}
 +	if(success)
 +	{
 +		success = check_write(apr_file, (void*)&mDupeCount, sizeof(S32));
 +	}
 +	if(success)
 +	{
 +		success = check_write(apr_file, (void*)&mCRCChangeCount, sizeof(S32));
 +	}
 +	if(success)
 +	{
 +		S32 size = mDP.getBufferSize();
 +		success = check_write(apr_file, (void*)&size, sizeof(S32));
 +	
 +		if(success)
 +		{
 +			success = check_write(apr_file, (void*)mBuffer, size);
 +		}
 +	}
 +
 +	return success ;
 +}
 +
 +//-------------------------------------------------------------------
 +//LLVOCache
 +//-------------------------------------------------------------------
 +// Format string used to construct filename for the object cache
 +static const char OBJECT_CACHE_FILENAME[] = "objects_%d_%d.slc";
 +
 +// Throw out 1/20 (5%) of our cache entries if we run out of room.
 +const U32 ENTRIES_PURGE_FACTOR = 20;
 +const char* object_cache_dirname = "objectcache";
 +const char* header_filename = "object.cache";
 +
 +LLVOCache* LLVOCache::sInstance = NULL;
 +
 +//static 
 +LLVOCache* LLVOCache::getInstance() 
 +{	
 +	if(!sInstance)
 +	{
 +		sInstance = new LLVOCache() ;
 +	}
 +	return sInstance ;
 +}
 +
 +//static 
 +BOOL LLVOCache::hasInstance() 
 +{
 +	return sInstance != NULL ;
 +}
 +
 +//static 
 +void LLVOCache::destroyClass() 
 +{
 +	if(sInstance)
 +	{
 +		delete sInstance ;
 +		sInstance = NULL ;
 +	}
 +}
 +
 +LLVOCache::LLVOCache():
 +	mInitialized(FALSE),
 +	mReadOnly(TRUE),
 +	mCacheSize(1)
 +{
 +	mEnabled = gSavedSettings.getBOOL("ObjectCacheEnabled");
 +	mLocalAPRFilePoolp = new LLVolatileAPRPool() ;
 +}
 +
 +LLVOCache::~LLVOCache()
 +{
 +	if(mEnabled)
 +	{
 +		writeCacheHeader();
 +		clearCacheInMemory();
 +	}
 +	delete mLocalAPRFilePoolp;
 +}
 +
 +void LLVOCache::setDirNames(ELLPath location)
 +{
 +	std::string delem = gDirUtilp->getDirDelimiter();
 +
 +	mHeaderFileName = gDirUtilp->getExpandedFilename(location, object_cache_dirname, header_filename);
 +	mObjectCacheDirName = gDirUtilp->getExpandedFilename(location, object_cache_dirname);
 +}
 +
 +void LLVOCache::initCache(ELLPath location, U32 size, U32 cache_version)
 +{
 +	if(!mEnabled)
 +	{
 +		llwarns << "Not initializing cache: Cache is currently disabled." << llendl;
 +		return ;
 +	}
 +
 +	if(mInitialized)
 +	{
 +		llwarns << "Cache already initialized." << llendl;
 +		return ;
 +	}
 +
 +	setDirNames(location);
 +	if (!mReadOnly)
 +	{
 +		LLFile::mkdir(mObjectCacheDirName);
 +	}
 +
 +	mCacheSize = size;
 +
 +	readCacheHeader();
 +	mInitialized = TRUE ;
 +
 +	if(mMetaInfo.mVersion != cache_version) 
 +	{
 +		mMetaInfo.mVersion = cache_version ;
 +		if(mReadOnly) //disable cache
 +		{
 +			clearCacheInMemory();
 +		}
 +		else //delete the current cache if the format does not match.
 +		{			
 +			removeCache();
 +		}
 +	}	
 +}
 +	
 +void LLVOCache::removeCache(ELLPath location) 
 +{
 +	if(mReadOnly)
 +	{
 +		llwarns << "Not removing cache at " << location << ": Cache is currently in read-only mode." << llendl;
 +		return ;
 +	}
 +
 +	std::string delem = gDirUtilp->getDirDelimiter();
 +	std::string mask = delem + "*";
 +	std::string cache_dir = gDirUtilp->getExpandedFilename(location, object_cache_dirname);
 +	llinfos << "Removing cache at " << cache_dir << llendl;
 +	gDirUtilp->deleteFilesInDir(cache_dir, mask); //delete all files
 +	LLFile::rmdir(cache_dir);
 +
 +	clearCacheInMemory();
 +	mInitialized = FALSE ;
 +}
 +
 +void LLVOCache::removeCache() 
 +{
 +	llassert_always(mInitialized) ;
 +	if(mReadOnly)
 +	{
 +		llwarns << "Not clearing object cache: Cache is currently in read-only mode." << llendl;
 +		return ;
 +	}
 +
 +	std::string delem = gDirUtilp->getDirDelimiter();
 +	std::string mask = delem + "*";
 +	llinfos << "Removing cache at " << mObjectCacheDirName << llendl;
 +	gDirUtilp->deleteFilesInDir(mObjectCacheDirName, mask); 
 +
 +	clearCacheInMemory() ;
 +	writeCacheHeader();
 +}
 +
 +void LLVOCache::clearCacheInMemory()
 +{
 +	std::for_each(mHandleEntryMap.begin(), mHandleEntryMap.end(), DeletePairedPointer());
 +	mHandleEntryMap.clear();
 +}
 +
 +void LLVOCache::getObjectCacheFilename(U64 handle, std::string& filename) 
 +{
 +	U32 region_x, region_y;
 +
 +	grid_from_region_handle(handle, ®ion_x, ®ion_y);
 +	filename = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, object_cache_dirname,
 +			   llformat(OBJECT_CACHE_FILENAME, region_x, region_y));
 +
 +	return ;
 +}
 +
 +void LLVOCache::removeFromCache(U64 handle)
 +{
 +	if(mReadOnly)
 +	{
 +		llwarns << "Not removing cache for handle " << handle << ": Cache is currently in read-only mode." << llendl;
 +		return ;
 +	}
 +
 +	std::string filename;
 +	getObjectCacheFilename(handle, filename);
 +	LLAPRFile::remove(filename, mLocalAPRFilePoolp);	
 +}
 +
 +BOOL LLVOCache::checkRead(LLAPRFile* apr_file, void* src, S32 n_bytes, bool remove_cache_on_error)
 +{
 +	if(!check_read(apr_file, src, n_bytes))
 +	{
 +		if (remove_cache_on_error)
 +		{
 +			removeCache() ;
 +		}
 +		return FALSE ;
 +	}
 +
 +	return TRUE ;
 +}
 +
 +BOOL LLVOCache::checkWrite(LLAPRFile* apr_file, void* src, S32 n_bytes, bool remove_cache_on_error) 
 +{
 +	if(!check_write(apr_file, src, n_bytes))
 +	{
 +		if (remove_cache_on_error)
 +		{
 +			removeCache() ;
 +		}
 +		return FALSE ;
 +	}
 +
 +	return TRUE ;
 +}
 +
 +void LLVOCache::readCacheHeader()
 +{
 +	if(!mEnabled)
 +	{
 +		llwarns << "Not reading cache header: Cache is currently disabled." << llendl;
 +		return;
 +	}
 +
 +	//clear stale info.
 +	clearCacheInMemory();	
 +
 +	if (LLAPRFile::isExist(mHeaderFileName, mLocalAPRFilePoolp))
 +	{
 +		LLAPRFile* apr_file = new LLAPRFile(mHeaderFileName, APR_FOPEN_READ|APR_FOPEN_BINARY, mLocalAPRFilePoolp);		
 +		
 +		//read the meta element
 +		bool remove_cache_on_error = false;
 +		if(!checkRead(apr_file, &mMetaInfo, sizeof(HeaderMetaInfo), remove_cache_on_error))
 +		{
 +			llwarns << "Error reading meta information from cache header." << llendl;
 +			delete apr_file;
 +			return;
 +		}
 +
 +		HeaderEntryInfo* entry ;
 +		for(U32 entry_index = 0; entry_index < mCacheSize; ++entry_index)
 +		{
 +			entry = new HeaderEntryInfo() ;
 +			if(!checkRead(apr_file, entry, sizeof(HeaderEntryInfo), remove_cache_on_error))
 +			{
 +				llwarns << "Error reading cache header entry. (entry_index=" << entry_index << ")" << llendl;
 +				delete entry ;			
 +				break;
 +			}
 +			else if(!entry->mTime) //end of the cache.
 +			{
 +				delete entry ;
 +				break;
 +			}
 +
 +			entry->mIndex = entry_index;
 +			mHandleEntryMap[entry->mHandle] = entry;
 +		}
 +
 +		delete apr_file ;
 +	}
 +	else
 +	{
 +		writeCacheHeader() ;
 +	}
 +}
 +
 +void LLVOCache::writeCacheHeader()
 +{
 +	if (!mEnabled)
 +	{
 +		llwarns << "Not writing cache header: Cache is currently disabled." << llendl;
 +		return;
 +	}
 +
 +	if(mReadOnly)
 +	{
 +		llwarns << "Not writing cache header: Cache is currently in read-only mode." << llendl;
 +		return;
 +	}
 +
 +	LLAPRFile* apr_file = new LLAPRFile(mHeaderFileName, APR_FOPEN_CREATE|APR_FOPEN_WRITE|APR_FOPEN_BINARY|APR_FOPEN_TRUNCATE, mLocalAPRFilePoolp);
 +
 +	//write the meta element
 +	if(!checkWrite(apr_file, &mMetaInfo, sizeof(HeaderMetaInfo)))
 +	{
 +		llwarns << "Error writing meta information to cache header." << llendl;
 +		delete apr_file;
 +		return;
 +	}
 +
 +	U32 entry_index = 0;
 +	handle_entry_map_t::iterator iter_end = mHandleEntryMap.end();
 +	for(handle_entry_map_t::iterator iter = mHandleEntryMap.begin();
 +		iter != iter_end;
 +		++iter)
 +	{
 +		HeaderEntryInfo* entry = iter->second;
 +		entry->mIndex = entry_index++;
 +		if(!checkWrite(apr_file, (void*)entry, sizeof(HeaderEntryInfo)))
 +		{
 +			llwarns << "Failed to write cache header for entry " << entry->mHandle << " (entry_index = " << entry_index << ")" << llendl;
 +			delete apr_file;
 +			return;
 +		}
 +	}
 +
 +	// Why do we need to fill the cache header with default entries?  DK 2010-12-14
 +	// It looks like we currently rely on the file being pre-allocated so we can seek during updateEntry().
 +	if(entry_index < mCacheSize)
 +	{
 +		HeaderEntryInfo* entry = new HeaderEntryInfo() ;
 +		for(; entry_index < mCacheSize; ++entry_index)
 +		{
 +			//fill the cache with the default entry.
 +			if(!checkWrite(apr_file, entry, sizeof(HeaderEntryInfo)))
 +			{
 +				llwarns << "Failed to fill cache header with default entries (entry_index = " << entry_index << ").  Switching to read-only mode." << llendl;
 +				mReadOnly = TRUE ; //disable the cache.
 +				break;
 +			}
 +		}
 +		delete entry ;
 +	}
 +	delete apr_file ;
 +}
 +
 +BOOL LLVOCache::updateEntry(const HeaderEntryInfo* entry)
 +{
 +	LLAPRFile* apr_file = new LLAPRFile(mHeaderFileName, APR_FOPEN_WRITE|APR_FOPEN_BINARY, mLocalAPRFilePoolp);
 +	apr_file->seek(APR_SET, entry->mIndex * sizeof(HeaderEntryInfo) + sizeof(HeaderMetaInfo)) ;
 +
 +	BOOL result = checkWrite(apr_file, (void*)entry, sizeof(HeaderEntryInfo)) ;
 +	delete apr_file;
 +	return result;
 +}
 +
 +void LLVOCache::readFromCache(U64 handle, const LLUUID& id, LLVOCacheEntry::vocache_entry_map_t& cache_entry_map) 
 +{
 +	if(!mEnabled)
 +	{
 +		llwarns << "Not reading cache for handle " << handle << "): Cache is currently disabled." << llendl;
 +		return ;
 +	}
 +	llassert_always(mInitialized);
 +
 +	handle_entry_map_t::iterator iter = mHandleEntryMap.find(handle) ;
 +	if(iter == mHandleEntryMap.end()) //no cache
 +	{
 +		llwarns << "No handle map entry for " << handle << llendl;
 +		return ;
 +	}
 +
 +	std::string filename;
 +	getObjectCacheFilename(handle, filename);
 +	LLAPRFile* apr_file = new LLAPRFile(filename, APR_FOPEN_READ|APR_FOPEN_BINARY, mLocalAPRFilePoolp);
 +
 +	LLUUID cache_id ;
 +	if(!checkRead(apr_file, cache_id.mData, UUID_BYTES))
 +	{
 +		llwarns << "Error reading cache_id from " << filename << llendl;
 +		delete apr_file;
 +		return ;
 +	}
 +	if(cache_id != id)
 +	{
 +		llwarns << "Cache ID (" << cache_id << ") doesn't match id for this region (" << id << "), discarding.  handle = " << handle << llendl;
 +		delete apr_file ;
 +		return ;
 +	}
 +
 +	S32 num_entries;
 +	if(!checkRead(apr_file, &num_entries, sizeof(S32)))
 +	{
 +		llwarns << "Error reading num_entries from " << filename << llendl;
 +		delete apr_file;
 +		return ;
 +	}
 +	
 +	for (S32 i = 0; i < num_entries; i++)
 +	{
 +		LLVOCacheEntry* entry = new LLVOCacheEntry(apr_file);
 +		if (!entry->getLocalID())
 +		{
 +			llwarns << "Aborting cache file load for " << filename << ", cache file corruption! (entry number = " << i << ")" << llendl;
 +			delete entry ;
 +			break;
 +		}
 +		cache_entry_map[entry->getLocalID()] = entry;
 +	}
 +
 +	delete apr_file ;
 +	return ;
 +}
 +	
 +void LLVOCache::purgeEntries()
 +{
 +	U32 limit = mCacheSize - (mCacheSize / ENTRIES_PURGE_FACTOR);
 +	limit = llclamp(limit, (U32)1, mCacheSize);
 +	// Construct a vector of entries out of the map so we can sort by time.
 +	std::vector<HeaderEntryInfo*> header_vector;
 +	handle_entry_map_t::iterator iter_end = mHandleEntryMap.end();
 +	for (handle_entry_map_t::iterator iter = mHandleEntryMap.begin();
 +		iter != iter_end;
 +		++iter)
 +	{
 +		header_vector.push_back(iter->second);
 +	}
 +	// Sort by time, oldest first.
 +	std::sort(header_vector.begin(), header_vector.end(), header_entry_less());
 +	while(header_vector.size() > limit)
 +	{
 +		HeaderEntryInfo* entry = header_vector.front();
 +		
 +		removeFromCache(entry->mHandle);
 +		mHandleEntryMap.erase(entry->mHandle);
 +		header_vector.erase(header_vector.begin());
 +		delete entry;
 +	}
 +
 +	writeCacheHeader() ;
 +	// *TODO: Verify that we can avoid re-reading the cache header.  DK 2010-12-14
 +	readCacheHeader() ;
 +}
 +
 +void LLVOCache::writeToCache(U64 handle, const LLUUID& id, const LLVOCacheEntry::vocache_entry_map_t& cache_entry_map, BOOL dirty_cache) 
 +{
 +	if(!mEnabled)
 +	{
 +		llwarns << "Not writing cache for handle " << handle << "): Cache is currently disabled." << llendl;
 +		return ;
 +	}
 +	llassert_always(mInitialized);
 +
 +	if(mReadOnly)
 +	{
 +		llwarns << "Not writing cache for handle " << handle << "): Cache is currently in read-only mode." << llendl;
 +		return ;
 +	}
 +
 +	U32 num_handle_entries = mHandleEntryMap.size();
 +	
 +	HeaderEntryInfo* entry;
 +	handle_entry_map_t::iterator iter = mHandleEntryMap.find(handle) ;
 +	U32 num_handle_entries = mHandleEntryMap.size();
 +	if(iter == mHandleEntryMap.end()) //new entry
 +	{
 +		if(num_handle_entries >= mCacheSize)
 +		{
 +			purgeEntries() ;
 +			num_handle_entries = mHandleEntryMap.size();
 +		}
 +		
 +		entry = new HeaderEntryInfo();
 +		entry->mHandle = handle ;
 +		entry->mTime = time(NULL) ;
 +		entry->mIndex = num_handle_entries++;
 +		mHandleEntryMap[handle] = entry ;
 +	}
 +	else
 +	{
 +		// Update access time.
 +		entry = iter->second ;
 +		entry->mTime = time(NULL) ;
 +	}
 +
 +	//update cache header
 +	if(!updateEntry(entry))
 +	{
 +		llwarns << "Failed to update cache header index " << entry->mIndex << ". handle = " << handle << llendl;
 +		return ; //update failed.
 +	}
 +
 +	if(!dirty_cache)
 +	{
 +		llwarns << "Skipping write to cache for handle " << handle << ": cache not dirty" << llendl;
 +		return ; //nothing changed, no need to update.
 +	}
 +
 +	//write to cache file
 +	std::string filename;
 +	getObjectCacheFilename(handle, filename);
 +	LLAPRFile* apr_file = new LLAPRFile(filename, APR_FOPEN_CREATE|APR_FOPEN_WRITE|APR_FOPEN_BINARY|APR_FOPEN_TRUNCATE, mLocalAPRFilePoolp);
 +	
 +	if(!checkWrite(apr_file, (void*)id.mData, UUID_BYTES))
 +	{
 +		llwarns << "Error writing id to " << filename << llendl;
 +		delete apr_file;
 +		return ;
 +	}
 +
 +	S32 num_entries = cache_entry_map.size() ;
 +	if(!checkWrite(apr_file, &num_entries, sizeof(S32)))
 +	{
 +		llwarns << "Error writing num_entries to " << filename << llendl;
 +		delete apr_file;
 +		return ;
 +	}
 +
 +	for (LLVOCacheEntry::vocache_entry_map_t::const_iterator iter = cache_entry_map.begin(); iter != cache_entry_map.end(); ++iter)
 +	{
 +		if(!iter->second->writeToFile(apr_file))
 +		{
 +			llwarns << "Aborting cache file write for " << filename << ", error writing to file!" << llendl;
 +			//failed
 +			removeCache() ;
 +			break;
 +		}
 +	}
 +
 +	delete apr_file ;
 +	return ;
 +}
 +
 diff --git a/indra/newview/llvocache.h b/indra/newview/llvocache.h index 014112718e..e103007979 100644 --- a/indra/newview/llvocache.h +++ b/indra/newview/llvocache.h @@ -128,8 +128,8 @@ private:  	void removeCache() ;  	void purgeEntries();  	BOOL updateEntry(const HeaderEntryInfo* entry); -	BOOL checkRead(LLAPRFile* apr_file, void* src, S32 n_bytes) ; -	BOOL checkWrite(LLAPRFile* apr_file, void* src, S32 n_bytes) ; +	BOOL checkRead(LLAPRFile* apr_file, void* src, S32 n_bytes, bool remove_cache_on_error = true) ; +	BOOL checkWrite(LLAPRFile* apr_file, void* src, S32 n_bytes, bool remove_cache_on_error = true) ;  private:  	BOOL                 mEnabled; diff --git a/indra/newview/llwaterparammanager.cpp b/indra/newview/llwaterparammanager.cpp index 4f6ec4ca61..d239347810 100644 --- a/indra/newview/llwaterparammanager.cpp +++ b/indra/newview/llwaterparammanager.cpp @@ -33,7 +33,6 @@  #include "pipeline.h"  #include "llsky.h" -#include "lldiriterator.h"  #include "llfloaterreg.h"  #include "llsliderctrl.h"  #include "llspinctrl.h" @@ -86,12 +85,11 @@ void LLWaterParamManager::loadAllPresets(const std::string& file_name)  	std::string path_name(gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "windlight/water", ""));  	LL_DEBUGS2("AppInit", "Shaders") << "Loading Default water settings from " << path_name << LL_ENDL; -	bool found = true; -	LLDirIterator app_settings_iter(path_name, "*.xml"); +	bool found = true;			  	while(found)   	{  		std::string name; -		found = app_settings_iter.next(name); +		found = gDirUtilp->getNextFileInDir(path_name, "*.xml", name);  		if(found)  		{ @@ -113,12 +111,11 @@ void LLWaterParamManager::loadAllPresets(const std::string& file_name)  	std::string path_name2(gDirUtilp->getExpandedFilename( LL_PATH_USER_SETTINGS , "windlight/water", ""));  	LL_DEBUGS2("AppInit", "Shaders") << "Loading User water settings from " << path_name2 << LL_ENDL; -	found = true; -	LLDirIterator user_settings_iter(path_name2, "*.xml"); +	found = true;			  	while(found)   	{  		std::string name; -		found = user_settings_iter.next(name); +		found = gDirUtilp->getNextFileInDir(path_name2, "*.xml", name);  		if(found)  		{  			name=name.erase(name.length()-4); diff --git a/indra/newview/llwlparammanager.cpp b/indra/newview/llwlparammanager.cpp index 848efcbb49..e5f52dfc97 100644 --- a/indra/newview/llwlparammanager.cpp +++ b/indra/newview/llwlparammanager.cpp @@ -31,7 +31,6 @@  #include "pipeline.h"  #include "llsky.h" -#include "lldiriterator.h"  #include "llfloaterreg.h"  #include "llsliderctrl.h"  #include "llspinctrl.h" @@ -101,12 +100,11 @@ void LLWLParamManager::loadPresets(const std::string& file_name)  	std::string path_name(gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "windlight/skies", ""));  	LL_DEBUGS2("AppInit", "Shaders") << "Loading Default WindLight settings from " << path_name << LL_ENDL; -	bool found = true; -	LLDirIterator app_settings_iter(path_name, "*.xml"); +	bool found = true;			  	while(found)   	{  		std::string name; -		found = app_settings_iter.next(name); +		found = gDirUtilp->getNextFileInDir(path_name, "*.xml", name);  		if(found)  		{ @@ -128,12 +126,11 @@ void LLWLParamManager::loadPresets(const std::string& file_name)  	std::string path_name2(gDirUtilp->getExpandedFilename( LL_PATH_USER_SETTINGS , "windlight/skies", ""));  	LL_DEBUGS2("AppInit", "Shaders") << "Loading User WindLight settings from " << path_name2 << LL_ENDL; -	found = true; -	LLDirIterator user_settings_iter(path_name2, "*.xml"); +	found = true;			  	while(found)   	{  		std::string name; -		found = user_settings_iter.next(name); +		found = gDirUtilp->getNextFileInDir(path_name2, "*.xml", name);  		if(found)  		{  			name=name.erase(name.length()-4); diff --git a/indra/newview/pipeline.h b/indra/newview/pipeline.h index 49269932f5..61264d380a 100644 --- a/indra/newview/pipeline.h +++ b/indra/newview/pipeline.h @@ -445,8 +445,9 @@ public:  		RENDER_DEBUG_AVATAR_VOLUME      = 0x0100000,  		RENDER_DEBUG_BUILD_QUEUE		= 0x0200000,  		RENDER_DEBUG_AGENT_TARGET       = 0x0400000, -		RENDER_DEBUG_PHYSICS_SHAPES     = 0x0800000, -		RENDER_DEBUG_NORMALS	        = 0x1000000, +		RENDER_DEBUG_UPDATE_TYPE		= 0x0800000, +		RENDER_DEBUG_PHYSICS_SHAPES     = 0x1000000, +		RENDER_DEBUG_NORMALS	        = 0x2000000,  	};  public: diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml index c9bc617a1a..6211561a5d 100644 --- a/indra/newview/skins/default/xui/en/menu_viewer.xml +++ b/indra/newview/skins/default/xui/en/menu_viewer.xml @@ -2208,6 +2208,16 @@             parameter="render batches" />          </menu_item_check>          <menu_item_check +         label="Update Type" +         name="Update Type"> +          <menu_item_check.on_check +           function="Advanced.CheckInfoDisplay" +           parameter="update type" /> +          <menu_item_check.on_click +           function="Advanced.ToggleInfoDisplay" +           parameter="update type" /> +        </menu_item_check> +        <menu_item_check           label="Texture Anim"           name="Texture Anim">            <menu_item_check.on_check diff --git a/indra/viewer_components/updater/tests/llupdaterservice_test.cpp b/indra/viewer_components/updater/tests/llupdaterservice_test.cpp index e19d5724f1..88ab5a2284 100644 --- a/indra/viewer_components/updater/tests/llupdaterservice_test.cpp +++ b/indra/viewer_components/updater/tests/llupdaterservice_test.cpp @@ -59,6 +59,12 @@ class LLDir_Mock : public LLDir  		return 0;  	} +	BOOL getNextFileInDir(const std::string &dirname,  +						  const std::string &mask,  +						  std::string &fname)  +	{ +		return false; +	}  	void getRandomFileInDir(const std::string &dirname,   							const std::string &mask,   							std::string &fname) {} | 
