2019-06-16 15:15:05 +00:00
|
|
|
use crate::dependency::Dependency;
|
2019-01-18 10:43:03 +00:00
|
|
|
use crate::runtime::ActiveQuery;
|
2019-06-23 12:15:37 +00:00
|
|
|
use crate::runtime::Durability;
|
2019-01-18 10:43:03 +00:00
|
|
|
use crate::runtime::Revision;
|
|
|
|
use crate::Database;
|
|
|
|
use std::cell::Ref;
|
|
|
|
use std::cell::RefCell;
|
|
|
|
|
|
|
|
/// State that is specific to a single execution thread.
|
|
|
|
///
|
|
|
|
/// Internally, this type uses ref-cells.
|
|
|
|
///
|
|
|
|
/// **Note also that all mutations to the database handle (and hence
|
|
|
|
/// to the local-state) must be undone during unwinding.**
|
|
|
|
pub(super) struct LocalState<DB: Database> {
|
|
|
|
/// Vector of active queries.
|
|
|
|
///
|
|
|
|
/// Unwinding note: pushes onto this vector must be popped -- even
|
|
|
|
/// during unwinding.
|
|
|
|
query_stack: RefCell<Vec<ActiveQuery<DB>>>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<DB: Database> Default for LocalState<DB> {
|
|
|
|
fn default() -> Self {
|
|
|
|
LocalState {
|
|
|
|
query_stack: Default::default(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<DB: Database> LocalState<DB> {
|
2019-06-25 09:44:37 +00:00
|
|
|
pub(super) fn push_query(
|
|
|
|
&self,
|
|
|
|
database_key: &DB::DatabaseKey,
|
|
|
|
max_durability: Durability,
|
|
|
|
) -> ActiveQueryGuard<'_, DB> {
|
2019-01-18 10:43:03 +00:00
|
|
|
let mut query_stack = self.query_stack.borrow_mut();
|
2019-06-25 09:44:37 +00:00
|
|
|
query_stack.push(ActiveQuery::new(database_key.clone(), max_durability));
|
2019-01-18 10:49:25 +00:00
|
|
|
ActiveQueryGuard {
|
|
|
|
local_state: self,
|
|
|
|
push_len: query_stack.len(),
|
|
|
|
}
|
2019-01-18 10:43:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns a reference to the active query stack.
|
|
|
|
///
|
|
|
|
/// **Warning:** Because this reference holds the ref-cell lock,
|
|
|
|
/// you should not use any mutating methods of `LocalState` while
|
|
|
|
/// reading from it.
|
|
|
|
pub(super) fn borrow_query_stack(&self) -> Ref<'_, Vec<ActiveQuery<DB>>> {
|
|
|
|
self.query_stack.borrow()
|
|
|
|
}
|
|
|
|
|
|
|
|
pub(super) fn query_in_progress(&self) -> bool {
|
|
|
|
!self.query_stack.borrow().is_empty()
|
|
|
|
}
|
|
|
|
|
2019-01-24 11:33:02 +00:00
|
|
|
pub(super) fn active_query(&self) -> Option<DB::DatabaseKey> {
|
2019-01-18 10:43:03 +00:00
|
|
|
self.query_stack
|
|
|
|
.borrow()
|
|
|
|
.last()
|
2019-01-24 11:33:02 +00:00
|
|
|
.map(|active_query| active_query.database_key.clone())
|
2019-01-18 10:43:03 +00:00
|
|
|
}
|
|
|
|
|
2019-06-22 03:12:51 +00:00
|
|
|
pub(super) fn report_query_read(
|
|
|
|
&self,
|
|
|
|
dependency: Dependency<DB>,
|
2019-06-23 12:15:37 +00:00
|
|
|
durability: Durability,
|
2019-06-22 03:12:51 +00:00
|
|
|
changed_at: Revision,
|
|
|
|
) {
|
2019-01-18 10:43:03 +00:00
|
|
|
if let Some(top_query) = self.query_stack.borrow_mut().last_mut() {
|
2019-06-23 12:15:37 +00:00
|
|
|
top_query.add_read(dependency, durability, changed_at);
|
2019-01-18 10:43:03 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub(super) fn report_untracked_read(&self, current_revision: Revision) {
|
|
|
|
if let Some(top_query) = self.query_stack.borrow_mut().last_mut() {
|
|
|
|
top_query.add_untracked_read(current_revision);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub(super) fn report_anon_read(&self, revision: Revision) {
|
|
|
|
if let Some(top_query) = self.query_stack.borrow_mut().last_mut() {
|
|
|
|
top_query.add_anon_read(revision);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-01-18 10:49:25 +00:00
|
|
|
|
2019-01-18 12:12:17 +00:00
|
|
|
impl<DB> std::panic::RefUnwindSafe for LocalState<DB> where DB: Database {}
|
|
|
|
|
2019-01-18 10:49:25 +00:00
|
|
|
/// When a query is pushed onto the `active_query` stack, this guard
|
|
|
|
/// is returned to represent its slot. The guard can be used to pop
|
|
|
|
/// the query from the stack -- in the case of unwinding, the guard's
|
|
|
|
/// destructor will also remove the query.
|
|
|
|
pub(super) struct ActiveQueryGuard<'me, DB: Database> {
|
|
|
|
local_state: &'me LocalState<DB>,
|
|
|
|
push_len: usize,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'me, DB> ActiveQueryGuard<'me, DB>
|
|
|
|
where
|
|
|
|
DB: Database,
|
|
|
|
{
|
|
|
|
fn pop_helper(&self) -> ActiveQuery<DB> {
|
|
|
|
let mut query_stack = self.local_state.query_stack.borrow_mut();
|
|
|
|
|
|
|
|
// Sanity check: pushes and pops should be balanced.
|
|
|
|
assert_eq!(query_stack.len(), self.push_len);
|
|
|
|
|
|
|
|
query_stack.pop().unwrap()
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Invoked when the query has successfully completed execution.
|
|
|
|
pub(super) fn complete(self) -> ActiveQuery<DB> {
|
|
|
|
let query = self.pop_helper();
|
|
|
|
std::mem::forget(self);
|
|
|
|
query
|
|
|
|
}
|
|
|
|
}
|
2019-01-18 10:52:47 +00:00
|
|
|
|
|
|
|
impl<'me, DB> Drop for ActiveQueryGuard<'me, DB>
|
|
|
|
where
|
|
|
|
DB: Database,
|
|
|
|
{
|
|
|
|
fn drop(&mut self) {
|
|
|
|
self.pop_helper();
|
|
|
|
}
|
|
|
|
}
|