mirror of
https://github.com/salsa-rs/salsa.git
synced 2025-01-12 16:35:21 +00:00
replace with_frozen_revision
with revision_guard
This commit is contained in:
parent
2cf73b45c1
commit
e6f1f6b7fb
2 changed files with 56 additions and 6 deletions
|
@ -12,6 +12,7 @@ readme = "README.md"
|
||||||
derive-new = "0.5.5"
|
derive-new = "0.5.5"
|
||||||
rustc-hash = "1.0"
|
rustc-hash = "1.0"
|
||||||
parking_lot = "0.6.4"
|
parking_lot = "0.6.4"
|
||||||
|
lock_api = "0.1.4"
|
||||||
indexmap = "1.0.1"
|
indexmap = "1.0.1"
|
||||||
log = "0.4.5"
|
log = "0.4.5"
|
||||||
smallvec = "0.6.5"
|
smallvec = "0.6.5"
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
use crate::Database;
|
use crate::Database;
|
||||||
|
use lock_api::RawRwLock;
|
||||||
use log::debug;
|
use log::debug;
|
||||||
use parking_lot::{Mutex, RwLock, RwLockReadGuard, RwLockUpgradableReadGuard};
|
use parking_lot::{Mutex, RwLock, RwLockReadGuard, RwLockUpgradableReadGuard};
|
||||||
use rustc_hash::{FxHashMap, FxHasher};
|
use rustc_hash::{FxHashMap, FxHasher};
|
||||||
|
@ -112,12 +113,28 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Implementation for the `with_frozen_revision` on
|
/// Locks the current revision and returns a guard object that --
|
||||||
/// `Database`. See the `Database` trait for more
|
/// when dropped -- will unlock it. While a revision is locked,
|
||||||
/// details.
|
/// queries can execute as normal but calls to `set` will block
|
||||||
pub fn with_frozen_revision<R>(&self, op: impl FnOnce() -> R) -> R {
|
/// (note that calls to `set` *do* set the cancellation flag,
|
||||||
let _lock = self.start_query();
|
/// which you can can check with
|
||||||
op()
|
/// `is_current_revision_canceled`). The intention is that you can
|
||||||
|
/// lock the revision and then do multiple queries, thus
|
||||||
|
/// guaranteeing that all of those queries execute against a
|
||||||
|
/// consistent "view" of the database.
|
||||||
|
///
|
||||||
|
/// Note that, unlike most RAII guards, the guard returned by this
|
||||||
|
/// method does not borrow the database or the runtime
|
||||||
|
/// (internally, it uses an `Arc` handle). This means it can be
|
||||||
|
/// sent to other threads without a problem -- the lock persists
|
||||||
|
/// as long as the guard has not yet been dropped.
|
||||||
|
///
|
||||||
|
/// ### Deadlock warning
|
||||||
|
///
|
||||||
|
/// If you invoke `lock_revision` and then, from the same thread,
|
||||||
|
/// call `set` on some input, you will get a deadlock.
|
||||||
|
pub fn lock_revision(&self) -> RevisionGuard<DB> {
|
||||||
|
RevisionGuard::new(&self.shared_state)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -406,6 +423,38 @@ impl<'db, DB: Database> Drop for QueryGuard<'db, DB> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The guard returned by `lock_revision`. Once this guard is dropped,
|
||||||
|
/// the revision will be unlocked, and calls to `set` can proceed.
|
||||||
|
pub struct RevisionGuard<DB: Database> {
|
||||||
|
shared_state: Arc<SharedState<DB>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<DB: Database> RevisionGuard<DB> {
|
||||||
|
/// Creates a new revision guard, acquiring the query read-lock in the process.
|
||||||
|
fn new(shared_state: &Arc<SharedState<DB>>) -> Self {
|
||||||
|
// Acquire the read-lock without using RAII. This requires the
|
||||||
|
// unsafe keyword because, if we were to unlock the lock this way,
|
||||||
|
// we would screw up other people using the safe APIs.
|
||||||
|
unsafe {
|
||||||
|
shared_state.query_lock.raw().lock_shared();
|
||||||
|
}
|
||||||
|
|
||||||
|
Self {
|
||||||
|
shared_state: shared_state.clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<DB: Database> Drop for RevisionGuard<DB> {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
// Release our read-lock without using RAII. As in `new`
|
||||||
|
// above, this requires the unsafe keyword.
|
||||||
|
unsafe {
|
||||||
|
self.shared_state.query_lock.raw().unlock_shared();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
struct ActiveQuery<DB: Database> {
|
struct ActiveQuery<DB: Database> {
|
||||||
/// What query is executing
|
/// What query is executing
|
||||||
descriptor: DB::QueryDescriptor,
|
descriptor: DB::QueryDescriptor,
|
||||||
|
|
Loading…
Reference in a new issue