async_skipdb/
optimistic.rs

1use std::{collections::hash_map::RandomState, hash::Hash};
2
3use super::*;
4
5mod write;
6pub use write::*;
7
8#[cfg(all(test, any(feature = "tokio", feature = "smol", feature = "async-std")))]
9mod tests;
10
11/// Database for [`smol`](https://crates.io/crates/smol) runtime.
12#[cfg(feature = "smol")]
13#[cfg_attr(docsrs, doc(cfg(feature = "smol")))]
14pub type SmolOptimisticDb<K, V, S = RandomState> = OptimisticDb<K, V, SmolSpawner, S>;
15
16/// Database for [`tokio`](https://crates.io/crates/tokio) runtime.
17#[cfg(feature = "tokio")]
18#[cfg_attr(docsrs, doc(cfg(feature = "tokio")))]
19pub type TokioOptimisticDb<K, V, S = RandomState> = OptimisticDb<K, V, TokioSpawner, S>;
20
21/// Database for [`async-std`](https://crates.io/crates/async-std) runtime.
22#[cfg(feature = "async-std")]
23#[cfg_attr(docsrs, doc(cfg(feature = "async-std")))]
24pub type AsyncStdOptimisticDb<K, V, S = RandomState> = OptimisticDb<K, V, AsyncStdSpawner, S>;
25
26struct Inner<K, V, SP, S = RandomState>
27where
28  SP: AsyncSpawner,
29{
30  tm: AsyncTm<K, V, HashCm<K, S>, BTreePwm<K, V>, SP>,
31  map: SkipCore<K, V>,
32  hasher: S,
33}
34
35impl<K, V, SP: AsyncSpawner, S> Inner<K, V, SP, S> {
36  async fn new(name: &str, hasher: S) -> Self {
37    let tm = AsyncTm::<_, _, _, _, SP>::new(name, 0).await;
38    Self {
39      tm,
40      map: SkipCore::new(),
41      hasher,
42    }
43  }
44
45  async fn version(&self) -> u64 {
46    self.tm.version().await
47  }
48}
49
50/// A concurrent MVCC in-memory key-value database.
51///
52/// `OptimisticDb` requires key to be [`Ord`] and [`Hash`](Hash).
53///
54/// Comparing to [`SerializableDb`](crate::serializable::SerializableDb):
55/// 1. `SerializableDb` support full serializable snapshot isolation, which can detect both direct dependencies and indirect dependencies.
56/// 2. `SerializableDb` does not require key to implement [`Hash`](core::hash::Hash).
57/// 3. But, [`OptimisticDb`](crate::optimistic::OptimisticDb) has more flexible write transaction APIs and no clone happen.
58pub struct OptimisticDb<K, V, SP: AsyncSpawner, S = RandomState> {
59  inner: Arc<Inner<K, V, SP, S>>,
60}
61
62#[doc(hidden)]
63impl<K, V, SP, S> AsSkipCore<K, V> for OptimisticDb<K, V, SP, S>
64where
65  SP: AsyncSpawner,
66{
67  #[inline]
68  fn as_inner(&self) -> &SkipCore<K, V> {
69    &self.inner.map
70  }
71}
72
73impl<K, V, SP, S> Clone for OptimisticDb<K, V, SP, S>
74where
75  SP: AsyncSpawner,
76{
77  #[inline]
78  fn clone(&self) -> Self {
79    Self {
80      inner: self.inner.clone(),
81    }
82  }
83}
84
85impl<K, V, SP: AsyncSpawner> OptimisticDb<K, V, SP> {
86  /// Creates a new `OptimisticDb` with the given options.
87  #[inline]
88  pub async fn new() -> Self {
89    Self::with_hasher(Default::default()).await
90  }
91}
92
93impl<K, V, SP: AsyncSpawner, S> OptimisticDb<K, V, SP, S> {
94  /// Creates a new `OptimisticDb` with the given hasher.
95  #[inline]
96  pub async fn with_hasher(hasher: S) -> Self {
97    let inner = Arc::new(Inner::<_, _, SP, _>::new(core::any::type_name::<Self>(), hasher).await);
98    Self { inner }
99  }
100
101  /// Returns the current read version of the database.
102  #[inline]
103  pub async fn version(&self) -> u64 {
104    self.inner.version().await
105  }
106
107  /// Create a read transaction.
108  #[inline]
109  pub async fn read(&self) -> ReadTransaction<K, V, OptimisticDb<K, V, SP, S>, HashCm<K, S>, SP> {
110    ReadTransaction::new(self.clone(), self.inner.tm.read().await)
111  }
112}
113
114impl<K, V, SP, S> OptimisticDb<K, V, SP, S>
115where
116  K: Ord + Hash + Eq,
117  S: BuildHasher + Clone,
118  SP: AsyncSpawner,
119{
120  /// Create a write transaction.
121  #[inline]
122  pub async fn write(&self) -> OptimisticTransaction<K, V, SP, S> {
123    OptimisticTransaction::new(self.clone(), None).await
124  }
125
126  /// Create a write transaction with the given capacity hint.
127  #[inline]
128  pub async fn write_with_capacity(&self, capacity: usize) -> OptimisticTransaction<K, V, SP, S> {
129    OptimisticTransaction::new(self.clone(), Some(capacity)).await
130  }
131}
132
133impl<K, V, SP, S> OptimisticDb<K, V, SP, S>
134where
135  K: Ord + Eq + Hash + Send + 'static,
136  V: Send + 'static,
137  SP: AsyncSpawner,
138{
139  /// Compact the database.
140  #[inline]
141  pub fn compact(&self) {
142    self.inner.map.compact(self.inner.tm.discard_hint());
143  }
144}