Cancel computation + fix invalidating cache

This commit is contained in:
elvis
2025-12-15 21:37:33 +01:00
parent 827895de3b
commit 28bd345d2c
2 changed files with 39 additions and 8 deletions

View File

@ -1,6 +1,7 @@
use std::borrow::Cow; use std::borrow::Cow;
use std::collections::HashMap; use std::collections::HashMap;
use std::hash::Hash; use std::hash::Hash;
use std::sync::atomic::AtomicBool;
use std::sync::{Arc, Mutex, RwLock}; use std::sync::{Arc, Mutex, RwLock};
use eframe::egui::text::LayoutJob; use eframe::egui::text::LayoutJob;
@ -1587,6 +1588,8 @@ pub struct AppHandle {
#[cfg(not(target_arch = "wasm32"))] #[cfg(not(target_arch = "wasm32"))]
app_logic_thread: Option<JoinHandle<anyhow::Result<()>>>, app_logic_thread: Option<JoinHandle<anyhow::Result<()>>>,
app_thread_stop: Arc<AtomicBool>,
} }
#[cfg(feature = "persistence")] #[cfg(feature = "persistence")]
@ -1935,6 +1938,7 @@ impl eframe::App for AppHandle {
.show(|ui| { .show(|ui| {
if ui.button("Clear").clicked() { if ui.button("Clear").clicked() {
self.cache.reset_cache(); self.cache.reset_cache();
self.cached_last_value = None;
ui.close(); ui.close();
} }
}); });
@ -1963,6 +1967,7 @@ impl eframe::App for AppHandle {
user_state.display_result = true; user_state.display_result = true;
self.cache.invalidate_last_state(); self.cache.invalidate_last_state();
self.cached_last_value = None; self.cached_last_value = None;
self.app_thread_stop.store(false, std::sync::atomic::Ordering::Relaxed);
}, },
| NodeResponse::User(CustomResponse::ClearActiveNode) => { | NodeResponse::User(CustomResponse::ClearActiveNode) => {
let mut user_state = self.user_state.write().unwrap(); let mut user_state = self.user_state.write().unwrap();
@ -1983,17 +1988,23 @@ impl eframe::App for AppHandle {
self.cache.invalidate_last_state(); self.cache.invalidate_last_state();
self.cached_last_value = None; self.cached_last_value = None;
}, },
| NodeResponse::DisconnectEvent { output, input: _ } => { | NodeResponse::DisconnectEvent { output: _, input } => {
self.cache.invalidate_cache(output); self.cache.invalidate_outputs(
&self.state.graph,
self.state.graph.get_input(*input).node
);
self.cache.invalidate_last_state(); self.cache.invalidate_last_state();
self.cached_last_value = None; self.cached_last_value = None;
}, },
| NodeResponse::ConnectEventEnded { | NodeResponse::ConnectEventEnded {
output, output: _,
input: _, input,
input_hook: _, input_hook: _,
} => { } => {
self.cache.invalidate_cache(output); self.cache.invalidate_outputs(
&self.state.graph,
self.state.graph.get_input(*input).node
);
self.cache.invalidate_last_state(); self.cache.invalidate_last_state();
self.cached_last_value = None; self.cached_last_value = None;
}, },
@ -2014,13 +2025,11 @@ impl eframe::App for AppHandle {
} else { } else {
#[cfg(not(target_arch = "wasm32"))] #[cfg(not(target_arch = "wasm32"))]
{ {
// wasm does not support threads :-(
// ---------------------------------------------------------
// did we already start a thread?
if self.app_logic_thread.is_none() { if self.app_logic_thread.is_none() {
let thread_join_handle = { let thread_join_handle = {
let arc_state = Arc::clone(&self.user_state); let arc_state = Arc::clone(&self.user_state);
let arc_translator = Arc::clone(&self.translator); let arc_translator = Arc::clone(&self.translator);
let cancel_computation = Arc::clone(&self.app_thread_stop);
let ctx = ctx.clone(); let ctx = ctx.clone();
let graph = self.state.graph.clone(); let graph = self.state.graph.clone();
let cache = self.cache.clone(); let cache = self.cache.clone();
@ -2030,6 +2039,7 @@ impl eframe::App for AppHandle {
graph, graph,
&cache, &cache,
arc_translator, arc_translator,
cancel_computation,
&ctx, &ctx,
) )
}) })
@ -2093,6 +2103,9 @@ impl eframe::App for AppHandle {
#[cfg(target_arch = "wasm32")] #[cfg(target_arch = "wasm32")]
{ {
// wasm does not support threads :-(
// ---------------------------------------------------------
// did we already start a thread?
let err = create_output( let err = create_output(
Arc::clone(&self.user_state), Arc::clone(&self.user_state),
self.state.graph.clone(), self.state.graph.clone(),
@ -2145,6 +2158,14 @@ impl eframe::App for AppHandle {
ui.vertical_centered(|ui| { ui.vertical_centered(|ui| {
egui::widgets::Spinner::new().ui(ui); egui::widgets::Spinner::new().ui(ui);
}); });
ui.separator();
ui.vertical_centered(|ui| {
if self.app_thread_stop.load(std::sync::atomic::Ordering::Relaxed) {
ui.label("Stopping computation");
} else if ui.button("Interrupt Computation").clicked() {
self.app_thread_stop.store(true, std::sync::atomic::Ordering::Relaxed);
}
});
}); });
} else { } else {
window.show(ctx, |ui| { window.show(ctx, |ui| {
@ -2164,6 +2185,7 @@ fn create_output(
graph: Graph<NodeData, BasicDataType, BasicValue>, graph: Graph<NodeData, BasicDataType, BasicValue>,
cache: &OutputsCache, cache: &OutputsCache,
translator: Arc<Mutex<rsprocess::translator::Translator>>, translator: Arc<Mutex<rsprocess::translator::Translator>>,
cancel_computation: Arc<AtomicBool>,
ctx: &egui::Context, ctx: &egui::Context,
) -> anyhow::Result<()> { ) -> anyhow::Result<()> {
let (save_node, active_node) = { let (save_node, active_node) = {
@ -2178,6 +2200,7 @@ fn create_output(
node, node,
cache, cache,
Arc::clone(&translator), Arc::clone(&translator),
Arc::clone(&cancel_computation),
ctx, ctx,
)?; )?;
let mut user_state = user_state.write().unwrap(); let mut user_state = user_state.write().unwrap();
@ -2189,6 +2212,7 @@ fn create_output(
node, node,
cache, cache,
Arc::clone(&translator), Arc::clone(&translator),
Arc::clone(&cancel_computation),
ctx, ctx,
)?; )?;
}, },

View File

@ -1,4 +1,5 @@
use std::collections::{HashSet, VecDeque}; use std::collections::{HashSet, VecDeque};
use std::sync::atomic::AtomicBool;
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
use egui_node_graph2::*; use egui_node_graph2::*;
@ -20,6 +21,7 @@ pub fn evaluate_node(
node_id: NodeId, node_id: NodeId,
outputs_cache: &OutputsCache, outputs_cache: &OutputsCache,
translator: Arc<Mutex<rsprocess::translator::Translator>>, translator: Arc<Mutex<rsprocess::translator::Translator>>,
cancel_computation: Arc<AtomicBool>,
ctx: &eframe::egui::Context, ctx: &eframe::egui::Context,
) -> anyhow::Result<()> { ) -> anyhow::Result<()> {
// generates list of nodes to evaluate and invalidates cache of those nodes // generates list of nodes to evaluate and invalidates cache of those nodes
@ -37,6 +39,11 @@ pub fn evaluate_node(
// for each node to evaluate (in the correct order) finds the output and // for each node to evaluate (in the correct order) finds the output and
// populates the cache // populates the cache
for node_id in to_evaluate { for node_id in to_evaluate {
// return early if someone asked
if cancel_computation.load(std::sync::atomic::Ordering::Acquire) {
anyhow::bail!("Computation Interrupted");
}
let node = &graph[node_id]; let node = &graph[node_id];
let outputs = graph[node_id].user_data.template.output(); let outputs = graph[node_id].user_data.template.output();
let output_names = let output_names =