diff --git a/src/runtime.rs b/src/runtime.rs index c83ad8ee..70aae023 100644 --- a/src/runtime.rs +++ b/src/runtime.rs @@ -1,8 +1,9 @@ use crate::Query; use crate::QueryContext; +use rustc_hash::FxHashMap; use std::cell::RefCell; use std::fmt::Write; -use std::sync::atomic::AtomicU64; +use std::sync::atomic::{AtomicU64, Ordering}; use std::sync::Arc; pub struct Runtime @@ -10,9 +11,10 @@ where QC: QueryContext, { shared_state: Arc>, - execution_stack: RefCell>, + local_state: RefCell>, } +/// State that will be common to all threads (when we support multiple threads) struct SharedState where QC: QueryContext, @@ -21,9 +23,23 @@ where revision: AtomicU64, } +/// State that will be specific to a single execution threads (when we support multiple threads) +struct LocalState +where + QC: QueryContext, +{ + query_stack: Vec, +} + #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] pub struct Revision { - generation: usize, + generation: u64, +} + +impl Revision { + crate fn zero() -> Self { + Revision { generation: 0 } + } } impl Default for Runtime @@ -36,7 +52,9 @@ where storage: Default::default(), revision: Default::default(), }), - execution_stack: RefCell::default(), + local_state: RefCell::new(LocalState { + query_stack: Default::default(), + }), } } } @@ -49,6 +67,20 @@ where &self.shared_state.storage } + /// Read current value of the revision counter. + crate fn current_revision(&self) -> Revision { + Revision { + generation: self.shared_state.revision.load(Ordering::SeqCst), + } + } + + /// Increments the current revision counter and returns the new value. + crate fn increment_revision(&self) -> Revision { + Revision { + generation: 1 + self.shared_state.revision.fetch_add(1, Ordering::SeqCst), + } + } + crate fn execute_query_implementation( &self, query: &QC, @@ -58,23 +90,25 @@ where where Q: Query, { - self.execution_stack.borrow_mut().push(descriptor); + self.local_state.borrow_mut().query_stack.push(descriptor); let value = Q::execute(query, key.clone()); - self.execution_stack.borrow_mut().pop(); + self.local_state.borrow_mut().query_stack.pop(); value } /// Obviously, this should be user configurable at some point. crate fn report_unexpected_cycle(&self, descriptor: QC::QueryDescriptor) -> ! { - let execution_stack = self.execution_stack.borrow(); - let start_index = (0..execution_stack.len()) + let local_state = self.local_state.borrow(); + let LocalState { query_stack, .. } = &*local_state; + + let start_index = (0..query_stack.len()) .rev() - .filter(|&i| execution_stack[i] == descriptor) + .filter(|&i| query_stack[i] == descriptor) .next() .unwrap(); let mut message = format!("Internal error, cycle detected:\n"); - for descriptor in &execution_stack[start_index..] { + for descriptor in &query_stack[start_index..] { writeln!(message, "- {:?}\n", descriptor).unwrap(); } panic!(message)