[Input] Cache parsed YAML files to speed up repeated reads
This commit is contained in:
parent
40c403c07d
commit
a5bf674419
4 changed files with 37 additions and 5 deletions
|
|
@ -340,6 +340,12 @@ private:
|
||||||
|
|
||||||
std::unordered_map<std::string, AnyValue> m_data;
|
std::unordered_map<std::string, AnyValue> m_data;
|
||||||
UnitSystem m_units;
|
UnitSystem m_units;
|
||||||
|
|
||||||
|
//! Cache for previously-parsed input (YAML) files. The key is the full path
|
||||||
|
//! to the file, and the second element of the value is the last-modified
|
||||||
|
//! time for the file, which is used to enable change detection.
|
||||||
|
static std::unordered_map<std::string, std::pair<AnyMap, int>> s_cache;
|
||||||
|
|
||||||
friend class AnyValue;
|
friend class AnyValue;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
// at http://www.cantera.org/license.txt for license and copyright information.
|
// at http://www.cantera.org/license.txt for license and copyright information.
|
||||||
|
|
||||||
#include "cantera/base/AnyMap.h"
|
#include "cantera/base/AnyMap.h"
|
||||||
|
#include "application.h"
|
||||||
#include "cantera/base/yaml.h"
|
#include "cantera/base/yaml.h"
|
||||||
#include "cantera/base/stringUtils.h"
|
#include "cantera/base/stringUtils.h"
|
||||||
#ifdef CT_USE_DEMANGLE
|
#ifdef CT_USE_DEMANGLE
|
||||||
|
|
@ -12,11 +13,14 @@
|
||||||
|
|
||||||
#include <boost/algorithm/string.hpp>
|
#include <boost/algorithm/string.hpp>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
#include <mutex>
|
||||||
|
|
||||||
namespace ba = boost::algorithm;
|
namespace ba = boost::algorithm;
|
||||||
|
|
||||||
namespace { // helper functions
|
namespace { // helper functions
|
||||||
|
|
||||||
|
std::mutex yaml_cache_mutex;
|
||||||
|
|
||||||
bool isFloat(const std::string& val)
|
bool isFloat(const std::string& val)
|
||||||
{
|
{
|
||||||
// This function duplicates the logic of fpValueCheck, but doesn't throw
|
// This function duplicates the logic of fpValueCheck, but doesn't throw
|
||||||
|
|
@ -238,6 +242,8 @@ std::map<std::string, std::string> AnyValue::s_typenames = {
|
||||||
{typeid(AnyMap).name(), "AnyMap"},
|
{typeid(AnyMap).name(), "AnyMap"},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
std::unordered_map<std::string, std::pair<AnyMap, int>> AnyMap::s_cache;
|
||||||
|
|
||||||
// Methods of class AnyValue
|
// Methods of class AnyValue
|
||||||
|
|
||||||
AnyValue::AnyValue()
|
AnyValue::AnyValue()
|
||||||
|
|
@ -745,17 +751,35 @@ AnyMap AnyMap::fromYamlString(const std::string& yaml) {
|
||||||
|
|
||||||
AnyMap AnyMap::fromYamlFile(const std::string& name) {
|
AnyMap AnyMap::fromYamlFile(const std::string& name) {
|
||||||
std::string fullName = findInputFile(name);
|
std::string fullName = findInputFile(name);
|
||||||
AnyMap amap;
|
int mtime = get_modified_time(fullName);
|
||||||
|
|
||||||
|
// Check for an already-parsed YAML file with the same last-modified time,
|
||||||
|
// and return that if possible
|
||||||
|
std::unique_lock<std::mutex> lock(yaml_cache_mutex);
|
||||||
|
auto iter = s_cache.find(fullName);
|
||||||
|
if (iter != s_cache.end() && iter->second.second == mtime) {
|
||||||
|
return iter->second.first;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate an AnyMap from the YAML file and store it in the cache
|
||||||
|
auto& cache_item = s_cache[fullName];
|
||||||
|
cache_item.second = mtime;
|
||||||
try {
|
try {
|
||||||
YAML::Node node = YAML::LoadFile(fullName);
|
YAML::Node node = YAML::LoadFile(fullName);
|
||||||
amap = node.as<AnyMap>();
|
cache_item.first = node.as<AnyMap>();
|
||||||
|
cache_item.first.applyUnits(UnitSystem());
|
||||||
} catch (YAML::Exception& err) {
|
} catch (YAML::Exception& err) {
|
||||||
std::ifstream infile(fullName);
|
std::ifstream infile(fullName);
|
||||||
|
s_cache.erase(fullName);
|
||||||
throw CanteraError("AnyMap::fromYamlFile",
|
throw CanteraError("AnyMap::fromYamlFile",
|
||||||
formatYamlError(err, infile, name));
|
formatYamlError(err, infile, name));
|
||||||
|
} catch (CanteraError& err) {
|
||||||
|
s_cache.erase(fullName);
|
||||||
|
throw;
|
||||||
}
|
}
|
||||||
amap.applyUnits(UnitSystem());
|
|
||||||
return amap;
|
// Return a copy of the AnyMap
|
||||||
|
return cache_item.first;
|
||||||
}
|
}
|
||||||
|
|
||||||
AnyMap::const_iterator begin(const AnyValue& v) {
|
AnyMap::const_iterator begin(const AnyValue& v) {
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,7 @@ static std::mutex app_mutex;
|
||||||
//! Mutex for controlling access to XML file storage
|
//! Mutex for controlling access to XML file storage
|
||||||
static std::mutex xml_mutex;
|
static std::mutex xml_mutex;
|
||||||
|
|
||||||
static int get_modified_time(const std::string& path) {
|
int get_modified_time(const std::string& path) {
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
HANDLE hFile = CreateFile(path.c_str(), NULL, NULL,
|
HANDLE hFile = CreateFile(path.c_str(), NULL, NULL,
|
||||||
NULL, OPEN_EXISTING, 0, NULL);
|
NULL, OPEN_EXISTING, 0, NULL);
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,8 @@ namespace Cantera
|
||||||
|
|
||||||
class XML_Node;
|
class XML_Node;
|
||||||
|
|
||||||
|
int get_modified_time(const std::string& path);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* @defgroup globalData Global Data
|
* @defgroup globalData Global Data
|
||||||
*
|
*
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue