summaryrefslogtreecommitdiff
path: root/indra/llxml
diff options
context:
space:
mode:
authorAlexander Gavriliuk <alexandrgproductengine@lindenlab.com>2024-03-05 17:03:11 +0100
committerGuru <alexandrgproductengine@lindenlab.com>2024-03-05 19:54:31 +0100
commita865d423974ea06dffa47798c81e98e7570b02ec (patch)
treed25f6c86d2948f7d8683aaa573d24135c8a26edb /indra/llxml
parent043a92997f187826ad26ff269613c8f0ed11379f (diff)
viewer#819 Avoid reading the same XML file multiple times
Diffstat (limited to 'indra/llxml')
-rw-r--r--indra/llxml/llcontrol.cpp24
-rw-r--r--indra/llxml/llcontrol.h2
-rw-r--r--indra/llxml/llxmlnode.cpp78
-rw-r--r--indra/llxml/llxmlnode.h26
-rw-r--r--indra/llxml/llxmltree.cpp45
-rw-r--r--indra/llxml/llxmltree.h4
6 files changed, 122 insertions, 57 deletions
diff --git a/indra/llxml/llcontrol.cpp b/indra/llxml/llcontrol.cpp
index e626bac7d0..71ba2b88bc 100644
--- a/indra/llxml/llcontrol.cpp
+++ b/indra/llxml/llcontrol.cpp
@@ -753,13 +753,13 @@ void LLControlGroup::setUntypedValue(std::string_view name, const LLSD& val)
//---------------------------------------------------------------
// Returns number of controls loaded, so 0 if failure
-U32 LLControlGroup::loadFromFileLegacy(const std::string& filename, bool require_declaration, eControlType declare_as)
+U32 LLControlGroup::loadFromFileLegacy(const std::string& filename, const std::string& xml, bool require_declaration, eControlType declare_as)
{
std::string name;
LLXmlTree xml_controls;
- if (!xml_controls.parseFile(filename))
+ if (!xml_controls.parseString(xml))
{
LL_WARNS("Settings") << "Unable to open control file " << filename << LL_ENDL;
return 0;
@@ -772,7 +772,7 @@ U32 LLControlGroup::loadFromFileLegacy(const std::string& filename, bool require
return 0;
}
- U32 validitems = 0;
+ U32 validitems = 0;
S32 version;
rootp->getAttributeS32("version", version);
@@ -990,24 +990,24 @@ U32 LLControlGroup::saveToFile(const std::string& filename, bool nondefault_only
U32 LLControlGroup::loadFromFile(const std::string& filename, bool set_default_values, bool save_values)
{
LLSD settings;
- llifstream infile;
- infile.open(filename.c_str());
- if(!infile.is_open())
+
+ std::string xml = gDirUtilp->getFileContents(filename);
+ if (xml.empty())
{
LL_WARNS("Settings") << "Cannot find file " << filename << " to load." << LL_ENDL;
return 0;
}
- if (LLSDParser::PARSE_FAILURE == LLSDSerialize::fromXML(settings, infile))
+ std::stringstream stream(xml);
+ if (LLSDParser::PARSE_FAILURE == LLSDSerialize::fromXML(settings, stream))
{
- infile.close();
LL_WARNS("Settings") << "Unable to parse LLSD control file " << filename << ". Trying Legacy Method." << LL_ENDL;
- return loadFromFileLegacy(filename, true, TYPE_STRING);
+ return loadFromFileLegacy(filename, xml, true, TYPE_STRING);
}
U32 validitems = 0;
bool hidefromsettingseditor = false;
-
+
for(LLSD::map_const_iterator itr = settings.beginMap(); itr != settings.endMap(); ++itr)
{
LLControlVariable::ePersist persist = LLControlVariable::PERSIST_NONDFT;
@@ -1019,7 +1019,7 @@ U32 LLControlGroup::loadFromFile(const std::string& filename, bool set_default_v
persist = control_map["Persist"].asInteger()?
LLControlVariable::PERSIST_NONDFT : LLControlVariable::PERSIST_NO;
}
-
+
// Sometimes we want to use the settings system to provide cheap persistence, but we
// don't want the settings themselves to be easily manipulated in the UI because
// doing so can cause support problems. So we have this option:
@@ -1031,7 +1031,7 @@ U32 LLControlGroup::loadFromFile(const std::string& filename, bool set_default_v
{
hidefromsettingseditor = false;
}
-
+
// If the control exists just set the value from the input file.
LLControlVariable* existing_control = getControl(name);
if(existing_control)
diff --git a/indra/llxml/llcontrol.h b/indra/llxml/llcontrol.h
index a8bc584c48..e148b74292 100644
--- a/indra/llxml/llcontrol.h
+++ b/indra/llxml/llcontrol.h
@@ -300,7 +300,7 @@ public:
// Returns number of controls loaded, 0 if failed
// If require_declaration is false, will auto-declare controls it finds
// as the given type.
- U32 loadFromFileLegacy(const std::string& filename, bool require_declaration = true, eControlType declare_as = TYPE_STRING);
+ U32 loadFromFileLegacy(const std::string& filename, const std::string& xml, bool require_declaration = true, eControlType declare_as = TYPE_STRING);
U32 saveToFile(const std::string& filename, bool nondefault_only);
U32 loadFromFile(const std::string& filename, bool default_values = false, bool save_values = true);
void resetToDefaults();
diff --git a/indra/llxml/llxmlnode.cpp b/indra/llxml/llxmlnode.cpp
index 9c7ac66f01..627e99a1e6 100644
--- a/indra/llxml/llxmlnode.cpp
+++ b/indra/llxml/llxmlnode.cpp
@@ -650,34 +650,56 @@ bool LLXMLNode::updateNode(
return true;
}
-// static
-bool LLXMLNode::parseFile(const std::string& filename, LLXMLNodePtr& node, LLXMLNode* defaults_tree)
+static std::map<std::string, LLXMLNodePtr> sXMLCache;
+static LLSharedMutex sXMLCacheMutex;
+
+static void saveToCache(const std::string& filename, LLXMLNodePtr& node)
{
- // Read file
- LL_DEBUGS("XMLNode") << "parsing XML file: " << filename << LL_ENDL;
- LLFILE* fp = LLFile::fopen(filename, "rb"); /* Flawfinder: ignore */
- if (fp == NULL)
- {
- node = NULL ;
- return false;
- }
- fseek(fp, 0, SEEK_END);
- U32 length = ftell(fp);
- fseek(fp, 0, SEEK_SET);
+ LLExclusiveMutexLock lock(&sXMLCacheMutex);
+ sXMLCache.emplace(filename, node.notNull() ? node->deepCopy() : nullptr);
+}
- U8* buffer = new U8[length+1];
- size_t nread = fread(buffer, 1, length, fp);
- buffer[nread] = 0;
- fclose(fp);
+static bool loadFromCache(const std::string& filename, LLXMLNodePtr& node)
+{
+ LLSharedMutexLock lock(&sXMLCacheMutex);
+ auto it = sXMLCache.find(filename);
+ if (it == sXMLCache.end())
+ return false;
+ node = it->second.notNull() ? it->second->deepCopy() : nullptr;
+ return node.notNull();
+}
- bool rv = parseBuffer(buffer, nread, node, defaults_tree);
- delete [] buffer;
- return rv;
+// static
+bool LLXMLNode::parseFile(const std::string& filename, LLXMLNodePtr& node, LLXMLNode* defaults_tree, bool cacheable)
+{
+ // Try to read from cache
+ if (cacheable)
+ {
+ if (loadFromCache(filename, node))
+ return true;
+ }
+
+ std::string xml = gDirUtilp->getFileContents(filename);
+ if (xml.empty())
+ {
+ LL_WARNS("XMLNode") << "no XML file: " << filename << LL_ENDL;
+ }
+ else if (parseBuffer(xml.data(), xml.size(), node, defaults_tree))
+ {
+ if (cacheable)
+ {
+ saveToCache(filename, node);
+ }
+ return true;
+ }
+
+ node = nullptr;
+ return false;
}
// static
bool LLXMLNode::parseBuffer(
- U8* buffer,
+ const char* buffer,
U32 length,
LLXMLNodePtr& node,
LLXMLNode* defaults)
@@ -696,7 +718,7 @@ bool LLXMLNode::parseBuffer(
XML_SetUserData(my_parser, (void *)file_node_ptr);
// Do the parsing
- if (XML_Parse(my_parser, (const char *)buffer, length, true) != XML_STATUS_OK)
+ if (XML_Parse(my_parser, buffer, length, true) != XML_STATUS_OK)
{
LL_WARNS() << "Error parsing xml error code: "
<< XML_ErrorString(XML_GetErrorCode(my_parser))
@@ -824,18 +846,20 @@ bool LLXMLNode::isFullyDefault()
}
// static
-bool LLXMLNode::getLayeredXMLNode(LLXMLNodePtr& root,
- const std::vector<std::string>& paths)
+bool LLXMLNode::getLayeredXMLNode(LLXMLNodePtr& root, const std::vector<std::string>& paths, bool cacheable)
{
- if (paths.empty()) return false;
+ if (paths.empty())
+ {
+ return false;
+ }
std::string filename = paths.front();
if (filename.empty())
{
return false;
}
-
- if (!LLXMLNode::parseFile(filename, root, NULL))
+
+ if (!LLXMLNode::parseFile(filename, root, nullptr, cacheable))
{
LL_WARNS() << "Problem reading UI description file: " << filename << LL_ENDL;
return false;
diff --git a/indra/llxml/llxmlnode.h b/indra/llxml/llxmlnode.h
index d5b8b36d86..32aee057ed 100644
--- a/indra/llxml/llxmlnode.h
+++ b/indra/llxml/llxmlnode.h
@@ -126,34 +126,34 @@ public:
bool isNull();
bool deleteChild(LLXMLNode* child);
- void addChild(LLXMLNodePtr& new_child);
+ void addChild(LLXMLNodePtr& new_child);
void setParent(LLXMLNodePtr& new_parent); // reparent if necessary
- // Serialization
+ // Deserialization
static bool parseFile(
const std::string& filename,
- LLXMLNodePtr& node,
- LLXMLNode* defaults_tree);
+ LLXMLNodePtr& node,
+ LLXMLNode* defaults_tree,
+ bool cacheable = false);
static bool parseBuffer(
- U8* buffer,
+ const char* buffer,
U32 length,
- LLXMLNodePtr& node,
+ LLXMLNodePtr& node,
LLXMLNode* defaults);
static bool parseStream(
std::istream& str,
- LLXMLNodePtr& node,
+ LLXMLNodePtr& node,
LLXMLNode* defaults);
static bool updateNode(
LLXMLNodePtr& node,
LLXMLNodePtr& update_node);
-
- static bool getLayeredXMLNode(LLXMLNodePtr& root, const std::vector<std::string>& paths);
-
-
+
+ static bool getLayeredXMLNode(LLXMLNodePtr& root, const std::vector<std::string>& paths, bool cacheable = false);
+
// Write standard XML file header:
// <?xml version="1.0" encoding="utf-8" standalone="yes" ?>
static void writeHeaderToFile(LLFILE *out_file);
-
+
// Write XML to file with one attribute per line.
// XML escapes values as they are written.
void writeToFile(LLFILE *out_file, const std::string& indent = std::string(), bool use_type_decorations=true);
@@ -237,7 +237,7 @@ public:
// Setters
bool setAttributeString(const char* attr, const std::string& value);
-
+
void setBoolValue(const bool value) { setBoolValue(1, &value); }
void setByteValue(const U8 value, Encoding encoding = ENCODING_DEFAULT) { setByteValue(1, &value, encoding); }
void setIntValue(const S32 value, Encoding encoding = ENCODING_DEFAULT) { setIntValue(1, &value, encoding); }
diff --git a/indra/llxml/llxmltree.cpp b/indra/llxml/llxmltree.cpp
index be3bcf2a66..38321847c3 100644
--- a/indra/llxml/llxmltree.cpp
+++ b/indra/llxml/llxmltree.cpp
@@ -35,6 +35,7 @@
#include "v4math.h"
#include "llquaternion.h"
#include "lluuid.h"
+#include "lldir.h"
//////////////////////////////////////////////////////////////
// LLXmlTree
@@ -60,20 +61,37 @@ void LLXmlTree::cleanup()
mNodeNames.cleanup();
}
+bool LLXmlTree::parseFile(const std::string & filename, bool keep_contents)
+{
+ delete mRoot;
+ mRoot = NULL;
+
+ std::string xml = gDirUtilp->getFileContents(filename);
+ if (xml.empty())
+ {
+ LL_WARNS() << "LLXmlTree parse failed. No XML file: " << filename << LL_ENDL;
+ return false;
+ }
+
+ bool success = parseString(xml, keep_contents);
-bool LLXmlTree::parseFile(const std::string &path, bool keep_contents)
+ return success;
+}
+
+bool LLXmlTree::parseString(const std::string &xml, bool keep_contents)
{
delete mRoot;
mRoot = NULL;
LLXmlTreeParser parser(this);
- bool success = parser.parseFile( path, &mRoot, keep_contents );
- if( !success )
+ bool success = parser.parseString(xml, &mRoot, keep_contents);
+ if (!success)
{
S32 line_number = parser.getCurrentLineNumber();
const char* error = parser.getErrorString();
LL_WARNS() << "LLXmlTree parse failed. Line " << line_number << ": " << error << LL_ENDL;
}
+
return success;
}
@@ -536,6 +554,27 @@ bool LLXmlTreeParser::parseFile(const std::string &path, LLXmlTreeNode** root, b
return success;
}
+bool LLXmlTreeParser::parseString(const std::string& xml, LLXmlTreeNode** root, bool keep_contents)
+{
+ llassert( !mRoot );
+ llassert( !mCurrent );
+
+ mKeepContents = keep_contents;
+
+ bool success = LLXmlParser::parse(xml.data(), (int)xml.size(), true);
+
+ *root = mRoot;
+ mRoot = NULL;
+
+ if (success)
+ {
+ llassert(!mCurrent);
+ }
+
+ mCurrent = NULL;
+
+ return success;
+}
const std::string& LLXmlTreeParser::tabs()
{
diff --git a/indra/llxml/llxmltree.h b/indra/llxml/llxmltree.h
index 5d15c4c7f5..d47f26f731 100644
--- a/indra/llxml/llxmltree.h
+++ b/indra/llxml/llxmltree.h
@@ -56,6 +56,7 @@ public:
void cleanup();
virtual bool parseFile(const std::string &path, bool keep_contents = true);
+ virtual bool parseString(const std::string &xml, bool keep_contents = true);
LLXmlTreeNode* getRoot() { return mRoot; }
@@ -199,7 +200,8 @@ public:
LLXmlTreeParser(LLXmlTree* tree);
virtual ~LLXmlTreeParser();
- bool parseFile(const std::string &path, LLXmlTreeNode** root, bool keep_contents );
+ bool parseFile(const std::string &path, LLXmlTreeNode** root, bool keep_contents);
+ bool parseString(const std::string &xml, LLXmlTreeNode** root, bool keep_contents);
protected:
const std::string& tabs();