summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLoren Shih <seraph@lindenlab.com>2011-01-14 14:16:07 -0500
committerLoren Shih <seraph@lindenlab.com>2011-01-14 14:16:07 -0500
commitd82da834fa4026f2912406e9d39196ec7287f785 (patch)
tree173094ca3fc90abbea3686d274c8a2dcb7adabd6
parent584c7ecb4ed02e9ab039c6254ffc33331c31058c (diff)
parent939e8d8f74687e7cb857c55bb6a8082226f1202b (diff)
Automated merge up from viewer-development
-rw-r--r--etc/message.xml17
-rw-r--r--indra/cmake/Boost.cmake18
-rw-r--r--indra/integration_tests/llui_libtest/llui_libtest.cpp5
-rw-r--r--indra/linux_updater/linux_updater.cpp15
-rw-r--r--indra/llcommon/llfile.cpp11
-rw-r--r--indra/llcommon/llfile.h2
-rw-r--r--indra/llvfs/CMakeLists.txt7
-rw-r--r--indra/llvfs/lldir.cpp6
-rw-r--r--indra/llvfs/lldir.h25
-rw-r--r--indra/llvfs/lldir_linux.cpp62
-rw-r--r--indra/llvfs/lldir_linux.h1
-rw-r--r--indra/llvfs/lldir_mac.cpp61
-rw-r--r--indra/llvfs/lldir_mac.h1
-rw-r--r--indra/llvfs/lldir_solaris.cpp62
-rw-r--r--indra/llvfs/lldir_solaris.h1
-rw-r--r--indra/llvfs/lldir_win32.cpp61
-rw-r--r--indra/llvfs/lldir_win32.h3
-rw-r--r--indra/llvfs/lldiriterator.cpp203
-rw-r--r--indra/llvfs/lldiriterator.h87
-rw-r--r--indra/llvfs/tests/lldir_test.cpp38
-rw-r--r--indra/newview/CMakeLists.txt2
-rw-r--r--indra/newview/llappviewer.cpp19
-rw-r--r--indra/newview/llappviewerlinux.cpp5
-rw-r--r--indra/newview/llfloateruipreview.cpp26
-rw-r--r--indra/newview/llinventorymodelbackgroundfetch.cpp4
-rw-r--r--indra/newview/llinventoryobserver.cpp4
-rw-r--r--indra/newview/lllogchat.cpp4
-rw-r--r--indra/newview/llspatialpartition.cpp48
-rw-r--r--indra/newview/llviewerinventory.cpp8
-rw-r--r--indra/newview/llviewermedia.cpp4
-rw-r--r--indra/newview/llviewermenu.cpp4
-rw-r--r--indra/newview/llviewerobject.cpp16
-rw-r--r--indra/newview/llviewerobject.h8
-rw-r--r--indra/newview/llviewerobjectlist.cpp92
-rw-r--r--indra/newview/llviewerregion.cpp63
-rw-r--r--indra/newview/llviewerregion.h21
-rw-r--r--indra/newview/llviewerstatsrecorder.cpp258
-rw-r--r--indra/newview/llviewerstatsrecorder.h97
-rw-r--r--indra/newview/llvocache.cpp1427
-rw-r--r--indra/newview/llvocache.h4
-rw-r--r--indra/newview/llwaterparammanager.cpp11
-rw-r--r--indra/newview/llwlparammanager.cpp11
-rw-r--r--indra/newview/pipeline.h5
-rw-r--r--indra/newview/skins/default/xui/en/menu_viewer.xml10
-rw-r--r--indra/viewer_components/updater/tests/llupdaterservice_test.cpp6
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, &region_x, &region_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, &region_x, &region_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) {}