[Input] Cache parsed YAML files to speed up repeated reads

This commit is contained in:
Ray Speth 2019-01-09 00:23:23 -05:00
parent 40c403c07d
commit a5bf674419
4 changed files with 37 additions and 5 deletions

View file

@ -340,6 +340,12 @@ private:
std::unordered_map<std::string, AnyValue> m_data;
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;
};

View file

@ -4,6 +4,7 @@
// at http://www.cantera.org/license.txt for license and copyright information.
#include "cantera/base/AnyMap.h"
#include "application.h"
#include "cantera/base/yaml.h"
#include "cantera/base/stringUtils.h"
#ifdef CT_USE_DEMANGLE
@ -12,11 +13,14 @@
#include <boost/algorithm/string.hpp>
#include <fstream>
#include <mutex>
namespace ba = boost::algorithm;
namespace { // helper functions
std::mutex yaml_cache_mutex;
bool isFloat(const std::string& val)
{
// 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"},
};
std::unordered_map<std::string, std::pair<AnyMap, int>> AnyMap::s_cache;
// Methods of class AnyValue
AnyValue::AnyValue()
@ -745,17 +751,35 @@ AnyMap AnyMap::fromYamlString(const std::string& yaml) {
AnyMap AnyMap::fromYamlFile(const std::string& 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 {
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) {
std::ifstream infile(fullName);
s_cache.erase(fullName);
throw CanteraError("AnyMap::fromYamlFile",
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) {

View file

@ -38,7 +38,7 @@ static std::mutex app_mutex;
//! Mutex for controlling access to XML file storage
static std::mutex xml_mutex;
static int get_modified_time(const std::string& path) {
int get_modified_time(const std::string& path) {
#ifdef _WIN32
HANDLE hFile = CreateFile(path.c_str(), NULL, NULL,
NULL, OPEN_EXISTING, 0, NULL);

View file

@ -19,6 +19,8 @@ namespace Cantera
class XML_Node;
int get_modified_time(const std::string& path);
/*!
* @defgroup globalData Global Data
*