Skip to content

Commit

Permalink
fix shared dependency issue
Browse files Browse the repository at this point in the history
  • Loading branch information
ch1ffa committed Jan 26, 2025
1 parent 8256f39 commit 95b2cd8
Show file tree
Hide file tree
Showing 2 changed files with 84 additions and 8 deletions.
25 changes: 17 additions & 8 deletions crates/pico/src/memo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,10 @@ pub fn memo<Db: Database>(
if let Some(node) = db.storage_mut().derived_nodes().get_mut(&node_id) {
if node.value != value {
node.value = value;
node.time_updated = time_updated;
state = DidRecalculate::Recalculated;
}
node.dependencies = dependencies;
node.time_updated = time_updated;
node.time_verified = current_epoch;
} else {
db.storage_mut().derived_nodes().insert(
Expand Down Expand Up @@ -107,7 +107,9 @@ fn any_dependency_changed<Db: Database>(
NodeKind::Source(key) => {
source_node_changed_since(db, key, dependency.time_verified_or_updated)
}
NodeKind::Derived(dep_node_id) => derived_node_changed(db, dep_node_id),
NodeKind::Derived(dep_node_id) => {
derived_node_changed_since(db, dep_node_id, dependency.time_verified_or_updated)
}
})
}

Expand All @@ -118,17 +120,24 @@ fn source_node_changed_since<Db: Database>(db: &Db, key: Key, since: Epoch) -> b
}
}

fn derived_node_changed<Db: Database>(db: &mut Db, node_id: DerivedNodeId) -> bool {
fn derived_node_changed_since<Db: Database>(
db: &mut Db,
node_id: DerivedNodeId,
since: Epoch,
) -> bool {
if !db.storage().params().contains_key(&node_id.param_id) {
return true;
}
let inner_fn = if let Some(node) = db.storage().derived_nodes().get(&node_id) {
if node.time_updated > since {
return true;
}
node.inner_fn
} else {
return true;
};
if !db.storage().params().contains_key(&node_id.param_id) {
return true;
}
let state = memo(db, node_id, inner_fn);
matches!(state, DidRecalculate::Recalculated)
let did_recalculate = memo(db, node_id, inner_fn);
matches!(did_recalculate, DidRecalculate::Recalculated)
}

fn call_inner_fn_and_collect_dependencies<Db: Database>(
Expand Down
67 changes: 67 additions & 0 deletions crates/pico/tests/shared_dependency.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
use calc::{ast::Program, error::Result, eval::eval, lexer::Lexer, parser::Parser};
use pico::storage::DefaultStorage;
use pico_core::{database::Database, source::SourceId};
use pico_macros::{memo, Db, Source};

mod calc;

/// Assert that we correctly compare epochs when 2 queries share the same dependency,
/// i.e. use the same memoized `parse_ast` function
#[test]
fn shared_dependency() {
let mut state = TestDatabase::default();

let input = state.set(Input {
key: "input",
value: "2 + 2 * 2".to_string(),
});

let result = evaluate(&mut state, input);
assert_eq!(result, 6);
let result_exp = evaluate_exp(&mut state, input, 2);
assert_eq!(result_exp, 36);

let input = state.set(Input {
key: "input",
value: "3 * 3".to_string(),
});

let result = evaluate(&mut state, input);
assert_eq!(result, 9);
let result_exp = evaluate_exp(&mut state, input, 2);
assert_eq!(result_exp, 81);
}

#[derive(Debug, Default, Db)]
struct TestDatabase {
pub storage: DefaultStorage<Self>,
}

#[derive(Debug, Clone, PartialEq, Eq, Source)]
struct Input {
#[key]
pub key: &'static str,
pub value: String,
}

#[memo]
pub fn parse_ast(db: &mut TestDatabase, id: SourceId<Input>) -> Result<Program> {
let source_text = db.get(id);
let mut lexer = Lexer::new(source_text.value);
let mut parser = Parser::new(&mut lexer)?;
parser.parse_program()
}

#[memo]
pub fn evaluate(db: &mut TestDatabase, id: SourceId<Input>) -> i64 {
let ast = parse_ast(db, id).expect("ast must be correct");
eval(ast.expression).expect("value must be evaluated")
}

#[memo]
pub fn evaluate_exp(db: &mut TestDatabase, id: SourceId<Input>, exp: u32) -> i64 {
let ast = parse_ast(db, id).expect("ast must be correct");
eval(ast.expression)
.expect("value must be evaluated")
.pow(exp)
}

0 comments on commit 95b2cd8

Please sign in to comment.