mirror of
https://github.com/loot/libloot.git
synced 2026-07-27 14:16:01 -07:00
Decouple clearing condition cache from evaluating general messages
This commit is contained in:
@@ -120,6 +120,18 @@ public:
|
||||
*/
|
||||
virtual bool Evaluate(const std::string& condition) const = 0;
|
||||
|
||||
/**
|
||||
* @brief Clears the cache of metadata condition evaluation results.
|
||||
* @details As many conditions involve reading files and/or directories,
|
||||
* libloot caches the results of condition evaluation and reuses
|
||||
* those cached results in subsequent evaluations.
|
||||
*
|
||||
* Clearing the condition cache means that the next time a condition
|
||||
* is evaluated, it will be evaluated from scratch instead of using a
|
||||
* cached result.
|
||||
*/
|
||||
virtual void ClearConditionCache() = 0;
|
||||
|
||||
/**
|
||||
* @}
|
||||
* @name Non-plugin Data Access
|
||||
|
||||
@@ -52,6 +52,14 @@ bool Database::Evaluate(const std::string& condition) const {
|
||||
}
|
||||
}
|
||||
|
||||
void Database::ClearConditionCache() {
|
||||
try {
|
||||
return database_->clear_condition_cache();
|
||||
} catch (const ::rust::Error& e) {
|
||||
std::rethrow_exception(mapError(e));
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::string> Database::GetKnownBashTags() const {
|
||||
try {
|
||||
return convert<std::string>(database_->known_bash_tags());
|
||||
|
||||
@@ -26,6 +26,8 @@ public:
|
||||
|
||||
bool Evaluate(const std::string& condition) const override;
|
||||
|
||||
void ClearConditionCache() override;
|
||||
|
||||
std::vector<std::string> GetKnownBashTags() const override;
|
||||
|
||||
std::vector<Message> GetGeneralMessages(
|
||||
|
||||
@@ -94,6 +94,15 @@ impl Database {
|
||||
.map_err(Into::into)
|
||||
}
|
||||
|
||||
pub fn clear_condition_cache(&self) -> Result<(), VerboseError> {
|
||||
self.0
|
||||
.write()
|
||||
.map_err(DatabaseLockPoisonError::from)?
|
||||
.clear_condition_cache();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn known_bash_tags(&self) -> Result<Vec<String>, VerboseError> {
|
||||
Ok(self
|
||||
.0
|
||||
|
||||
@@ -266,6 +266,8 @@ mod ffi {
|
||||
|
||||
pub fn evaluate(&self, condition: &str) -> Result<bool>;
|
||||
|
||||
pub fn clear_condition_cache(&self) -> Result<()>;
|
||||
|
||||
pub fn known_bash_tags(&self) -> Result<Vec<String>>;
|
||||
|
||||
pub fn general_messages(&self, evaluate_conditions: bool) -> Result<Vec<Message>>;
|
||||
|
||||
@@ -277,6 +277,21 @@ TEST_P(DatabaseInterfaceTest, evaluateShouldReturnFalseIfTheConditionIsFalse) {
|
||||
EXPECT_FALSE(handle_->GetDatabase().Evaluate("file(\"missing.esp\")"));
|
||||
}
|
||||
|
||||
TEST_P(DatabaseInterfaceTest,
|
||||
clearConditionCacheShouldCauseConditionsToBeEvaluatedFromScratch) {
|
||||
const auto condition = "file(\"Blank.esp\")";
|
||||
|
||||
EXPECT_TRUE(handle_->GetDatabase().Evaluate(condition));
|
||||
|
||||
std::filesystem::remove(dataPath / "Blank.esp");
|
||||
|
||||
EXPECT_TRUE(handle_->GetDatabase().Evaluate(condition));
|
||||
|
||||
handle_->GetDatabase().ClearConditionCache();
|
||||
|
||||
EXPECT_FALSE(handle_->GetDatabase().Evaluate(condition));
|
||||
}
|
||||
|
||||
TEST_P(DatabaseInterfaceTest,
|
||||
getGroupsShouldReturnAllGroupsListedInTheLoadedMetadata) {
|
||||
ASSERT_NO_THROW(GenerateMasterlist());
|
||||
|
||||
@@ -128,6 +128,16 @@ impl Database {
|
||||
.map_err(Into::into)
|
||||
}
|
||||
|
||||
#[napi]
|
||||
pub fn clear_condition_cache(&self) -> Result<(), VerboseError> {
|
||||
self.0
|
||||
.write()
|
||||
.map_err(DatabaseLockPoisonError::from)?
|
||||
.clear_condition_cache();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[napi]
|
||||
pub fn known_bash_tags(&self) -> Result<Vec<String>, VerboseError> {
|
||||
Ok(self
|
||||
|
||||
@@ -98,6 +98,15 @@ impl Database {
|
||||
.map_err(Into::into)
|
||||
}
|
||||
|
||||
pub fn clear_condition_cache(&self) -> Result<(), VerboseError> {
|
||||
self.0
|
||||
.write()
|
||||
.map_err(DatabaseLockPoisonError::from)?
|
||||
.clear_condition_cache();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn known_bash_tags(&self) -> Result<Vec<String>, VerboseError> {
|
||||
Ok(self
|
||||
.0
|
||||
|
||||
+54
-41
@@ -75,13 +75,6 @@ impl Database {
|
||||
&mut self.condition_evaluator_state
|
||||
}
|
||||
|
||||
pub(crate) fn clear_condition_cache(&mut self) {
|
||||
if let Err(e) = self.condition_evaluator_state.clear_condition_cache() {
|
||||
logging::error!("The condition cache's lock is poisoned, assigning a new cache");
|
||||
*e.into_inner() = HashMap::new();
|
||||
}
|
||||
}
|
||||
|
||||
/// Loads the masterlist from the given path.
|
||||
///
|
||||
/// Replaces any existing data that was previously loaded from a masterlist.
|
||||
@@ -154,6 +147,22 @@ impl Database {
|
||||
evaluate_condition(condition, &self.condition_evaluator_state).map_err(Into::into)
|
||||
}
|
||||
|
||||
/// Clears the cache of metadata condition evaluation results.
|
||||
///
|
||||
/// As many conditions involve reading files and/or directories, libloot
|
||||
/// caches the results of condition evaluation and reuses those cached
|
||||
/// results in subsequent evaluations.
|
||||
///
|
||||
/// Clearing the condition cache means that the next time a condition is
|
||||
/// evaluated, it will be evaluated from scratch instead of using a cached
|
||||
/// result.
|
||||
pub fn clear_condition_cache(&mut self) {
|
||||
if let Err(e) = self.condition_evaluator_state.clear_condition_cache() {
|
||||
logging::error!("The condition cache's lock is poisoned, assigning a new cache");
|
||||
*e.into_inner() = HashMap::new();
|
||||
}
|
||||
}
|
||||
|
||||
/// Gets the Bash Tags that are listed in the loaded metadata lists.
|
||||
///
|
||||
/// Bash Tag suggestions can include Bash Tags not in this list.
|
||||
@@ -165,17 +174,10 @@ impl Database {
|
||||
}
|
||||
|
||||
/// Get all general messages listed in the loaded metadata lists.
|
||||
///
|
||||
/// Evaluating general message conditions also clears the condition cache
|
||||
/// before evaluating conditions.
|
||||
pub fn general_messages(
|
||||
&mut self,
|
||||
&self,
|
||||
evaluate_conditions: EvalMode,
|
||||
) -> Result<Vec<Message>, ConditionEvaluationError> {
|
||||
if evaluate_conditions == EvalMode::Evaluate {
|
||||
self.clear_condition_cache();
|
||||
}
|
||||
|
||||
let messages_iter = self
|
||||
.masterlist
|
||||
.messages()
|
||||
@@ -237,9 +239,6 @@ impl Database {
|
||||
}
|
||||
|
||||
/// Get all of a plugin's loaded metadata.
|
||||
///
|
||||
/// Evaluating plugin metadata conditions does **not** clear the condition
|
||||
/// cache.
|
||||
pub fn plugin_metadata(
|
||||
&self,
|
||||
plugin_name: &str,
|
||||
@@ -267,9 +266,6 @@ impl Database {
|
||||
}
|
||||
|
||||
/// Get a plugin's metadata loaded from the given userlist.
|
||||
///
|
||||
/// Evaluating plugin metadata conditions does **not** clear the condition
|
||||
/// cache.
|
||||
pub fn plugin_user_metadata(
|
||||
&self,
|
||||
plugin_name: &str,
|
||||
@@ -838,6 +834,43 @@ plugins:
|
||||
}
|
||||
}
|
||||
|
||||
mod evaluate {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn should_return_true_if_the_condition_is_true() {
|
||||
let fixture = Fixture::new(GameType::Oblivion);
|
||||
let database = fixture.database();
|
||||
|
||||
assert!(database.evaluate("file(\"Blank.esp\")").unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_return_false_if_the_condition_is_false() {
|
||||
let fixture = Fixture::new(GameType::Oblivion);
|
||||
let database = fixture.database();
|
||||
|
||||
assert!(!database.evaluate("file(\"missing.esp\")").unwrap());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn clear_condition_cache_should_cause_conditions_to_be_evaluated_from_scratch() {
|
||||
let fixture = Fixture::new(GameType::Oblivion);
|
||||
let condition = "file(\"Blank.esp\")";
|
||||
let mut database = fixture.database();
|
||||
|
||||
assert!(database.evaluate(condition).unwrap());
|
||||
|
||||
std::fs::remove_file(fixture.inner.data_path().join("Blank.esp")).unwrap();
|
||||
|
||||
assert!(database.evaluate(condition).unwrap());
|
||||
|
||||
database.clear_condition_cache();
|
||||
|
||||
assert!(!database.evaluate(condition).unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn known_bash_tags_should_append_userlist_tags_to_masterlist_tags() {
|
||||
let fixture = Fixture::new(GameType::Oblivion);
|
||||
@@ -914,26 +947,6 @@ plugins:
|
||||
}
|
||||
}
|
||||
|
||||
mod evaluate {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn should_return_true_if_the_condition_is_true() {
|
||||
let fixture = Fixture::new(GameType::Oblivion);
|
||||
let database = fixture.database();
|
||||
|
||||
assert!(database.evaluate("file(\"Blank.esp\")").unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_return_false_if_the_condition_is_false() {
|
||||
let fixture = Fixture::new(GameType::Oblivion);
|
||||
let database = fixture.database();
|
||||
|
||||
assert!(!database.evaluate("file(\"missing.esp\")").unwrap());
|
||||
}
|
||||
}
|
||||
|
||||
mod groups {
|
||||
use super::*;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user