Cache Function evaluation results, and use cached results

This commit is contained in:
Oliver Hamlet
2018-10-06 11:45:57 +01:00
parent 11a92511c1
commit 3404924752
3 changed files with 571 additions and 243 deletions
+34 -2
View File
@@ -193,7 +193,13 @@ fn evaluate_version(
impl Function {
pub fn eval(&self, state: &State) -> Result<bool, Error> {
match *self {
if let Ok(reader) = state.condition_cache.read() {
if let Some(cached_result) = reader.get(self) {
return Ok(*cached_result);
}
}
let result = match *self {
Function::FilePath(ref f) => evaluate_file_path(state, f),
Function::FileRegex(ref p, ref r) => evaluate_file_regex(state, p, r),
Function::ActivePath(ref p) => evaluate_active_path(state, p),
@@ -202,7 +208,15 @@ impl Function {
Function::ManyActive(ref r) => evaluate_many_active(state, r),
Function::Checksum(ref path, ref crc) => evaluate_checksum(state, path, *crc),
Function::Version(ref p, ref v, ref c) => evaluate_version(state, p, v, *c),
};
if let Ok(function_result) = result {
if let Ok(mut writer) = state.condition_cache.write() {
writer.insert(self.clone(), function_result);
}
}
result
}
}
@@ -210,7 +224,7 @@ impl Function {
mod tests {
use super::*;
use std::fs::{copy, create_dir};
use std::fs::{copy, create_dir, remove_file};
use std::sync::RwLock;
use regex::RegexBuilder;
@@ -261,6 +275,7 @@ mod tests {
.iter()
.map(|(p, v)| (p.to_lowercase(), v.to_string()))
.collect(),
condition_cache: RwLock::default(),
}
}
@@ -573,6 +588,23 @@ mod tests {
assert!(function.eval(&state).unwrap());
}
#[test]
fn function_eval_should_cache_results_and_use_cached_results() {
let tmp_dir = tempdir().unwrap();
let data_path = tmp_dir.path().join("Data");
let state = state(data_path);
copy(Path::new("Cargo.toml"), &state.data_path.join("Cargo.toml")).unwrap();
let function = Function::FilePath(PathBuf::from("Cargo.toml"));
assert!(function.eval(&state).unwrap());
remove_file(&state.data_path.join("Cargo.toml")).unwrap();
assert!(function.eval(&state).unwrap());
}
#[test]
fn function_version_eval_should_be_true_if_the_path_does_not_exist_and_comparator_is_ne() {
let function =
+521 -233
View File
File diff suppressed because it is too large Load Diff
+16 -8
View File
@@ -86,15 +86,22 @@ impl GameType {
pub struct State {
game_type: GameType,
/// Game Data folder path.
data_path: PathBuf,
/// Path to the LOOT executable, used to resolve conditions that use the "LOOT" path.
loot_path: PathBuf,
active_plugins: HashSet<String>, // Lowercased plugin filenames.
crc_cache: RwLock<HashMap<String, u32>>, // Lowercased paths.
plugin_versions: HashMap<String, String>, // Lowercased plugin filenames and their versions as found in description fields.
/// Lowercased plugin filenames.
active_plugins: HashSet<String>,
/// Lowercased paths.
crc_cache: RwLock<HashMap<String, u32>>,
/// Lowercased plugin filenames and their versions as found in description fields.
plugin_versions: HashMap<String, String>,
/// Conditions that have already been evaluated, and their results.
condition_cache: RwLock<HashMap<Function, bool>>,
}
// Compound conditions joined by 'or'
#[derive(Clone, Debug, Default, PartialEq, Eq)]
/// Compound conditions joined by 'or'
#[derive(Clone, Debug, Default, PartialEq, Eq, Hash)]
pub struct Expression(Vec<CompoundCondition>);
impl Expression {
@@ -124,8 +131,8 @@ impl fmt::Display for Expression {
}
}
// Conditions joined by 'and'
#[derive(Clone, Debug, Default, PartialEq, Eq)]
/// Conditions joined by 'and'
#[derive(Clone, Debug, Default, PartialEq, Eq, Hash)]
struct CompoundCondition(Vec<Condition>);
impl CompoundCondition {
@@ -154,7 +161,7 @@ impl fmt::Display for CompoundCondition {
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
enum Condition {
Function(Function),
InvertedFunction(Function),
@@ -219,6 +226,7 @@ mod tests {
active_plugins: HashSet::new(),
crc_cache: RwLock::default(),
plugin_versions: HashMap::default(),
condition_cache: RwLock::default(),
}
}