async_skipdb/
serializable.rs

1use async_txn::{AsyncSpawner, BTreeCm};
2pub use cheap_clone::CheapClone;
3
4use super::*;
5
6mod optimistic;
7pub use optimistic::*;
8
9#[allow(clippy::module_inception)]
10mod serializable;
11pub use serializable::*;
12
13/// Database for [`smol`](https://crates.io/crates/smol) runtime.
14#[cfg(feature = "smol")]
15#[cfg_attr(docsrs, doc(cfg(feature = "smol")))]
16pub type SmolSerializableDb<K, V> = SerializableDb<K, V, SmolSpawner>;
17
18/// Database for [`tokio`](https://crates.io/crates/tokio) runtime.
19#[cfg(feature = "tokio")]
20#[cfg_attr(docsrs, doc(cfg(feature = "tokio")))]
21pub type TokioSerializableDb<K, V> = SerializableDb<K, V, TokioSpawner>;
22
23/// Database for [`async-std`](https://crates.io/crates/async-std) runtime.
24#[cfg(feature = "async-std")]
25#[cfg_attr(docsrs, doc(cfg(feature = "async-std")))]
26pub type AsyncStdSerializableDb<K, V> = SerializableDb<K, V, AsyncStdSpawner>;
27
28struct Inner<K, V, S>
29where
30  S: AsyncSpawner,
31{
32  tm: AsyncTm<K, V, BTreeCm<K>, BTreePwm<K, V>, S>,
33  map: SkipCore<K, V>,
34}
35
36impl<K, V, S: AsyncSpawner> Inner<K, V, S> {
37  async fn new(name: &str) -> Self {
38    let tm = AsyncTm::new(name, 0).await;
39    Self {
40      tm,
41      map: SkipCore::new(),
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/// `SerializableDb` requires key to be [`Ord`] and [`CheapClone`].
53/// The [`CheapClone`] bound here hints the user that the key should be cheap to clone,
54/// because it will be cloned at least one time during the write transaction.
55///
56/// Comparing to [`OptimisticDb`](crate::optimistic::OptimisticDb):
57/// 1. `SerializableDb` support full serializable snapshot isolation, which can detect both direct dependencies and indirect dependencies.
58/// 2. `SerializableDb` does not require key to implement [`Hash`](core::hash::Hash).
59/// 3. But, [`OptimisticDb`](crate::optimistic::OptimisticDb) has more flexible write transaction APIs.
60pub struct SerializableDb<K, V, S: AsyncSpawner> {
61  inner: Arc<Inner<K, V, S>>,
62}
63
64#[doc(hidden)]
65impl<K, V, S: AsyncSpawner> AsSkipCore<K, V> for SerializableDb<K, V, S> {
66  #[inline]
67  #[allow(private_interfaces)]
68  fn as_inner(&self) -> &SkipCore<K, V> {
69    &self.inner.map
70  }
71}
72
73impl<K, V, S: AsyncSpawner> Clone for SerializableDb<K, V, S> {
74  #[inline]
75  fn clone(&self) -> Self {
76    Self {
77      inner: self.inner.clone(),
78    }
79  }
80}
81
82impl<K, V, S: AsyncSpawner> SerializableDb<K, V, S> {
83  /// Creates a new `SerializableDb`.
84  #[inline]
85  pub async fn new() -> Self {
86    Self {
87      inner: Arc::new(Inner::new(core::any::type_name::<Self>()).await),
88    }
89  }
90}
91
92impl<K, V, S: AsyncSpawner> SerializableDb<K, V, S> {
93  /// Returns the current read version of the database.
94  #[inline]
95  pub async fn version(&self) -> u64 {
96    self.inner.version().await
97  }
98
99  /// Create a read transaction.
100  #[inline]
101  pub async fn read(&self) -> ReadTransaction<K, V, SerializableDb<K, V, S>, BTreeCm<K>, S> {
102    ReadTransaction::new(self.clone(), self.inner.tm.read().await)
103  }
104}
105
106impl<K, V, S> SerializableDb<K, V, S>
107where
108  K: CheapClone + Ord,
109  S: AsyncSpawner,
110{
111  /// Create a optimistic write transaction.
112  ///
113  /// Optimistic write transaction is not a totally Serializable Snapshot Isolation transaction.
114  /// It can handle most of write skew anomaly, but not all. Basically, all directly dependencies
115  /// can be handled, but indirect dependencies (logical dependencies) can not be handled.
116  /// If you need a totally Serializable Snapshot Isolation transaction, you should use
117  /// [`SerializableDb::serializable_write`](SerializableDb::serializable_write) instead.
118  #[inline]
119  pub async fn optimistic_write(&self) -> OptimisticTransaction<K, V, S> {
120    OptimisticTransaction::new(self.clone()).await
121  }
122
123  /// Create a serializable write transaction.
124  ///
125  /// Serializable write transaction is a totally Serializable Snapshot Isolation transaction.
126  /// It can handle all kinds of write skew anomaly, including indirect dependencies (logical dependencies).
127  /// If in your code, you do not care about indirect dependencies (logical dependencies), you can use
128  /// [`SerializableDb::optimistic_write`](SerializableDb::optimistic_write) instead.
129  #[inline]
130  pub async fn serializable_write(&self) -> SerializableTransaction<K, V, S> {
131    SerializableTransaction::new(self.clone()).await
132  }
133}
134
135impl<K, V, S> SerializableDb<K, V, S>
136where
137  K: CheapClone + Ord + Send + 'static,
138  V: Send + 'static,
139  S: AsyncSpawner,
140{
141  /// Compact the database.
142  #[inline]
143  pub fn compact(&self) {
144    self.inner.map.compact(self.inner.tm.discard_hint());
145  }
146}