fjall/tx/write/
single_writer.rs

1use super::BaseTransaction as InnerWriteTransaction;
2use crate::{snapshot_nonce::SnapshotNonce, PersistMode, TxKeyspace, TxPartitionHandle};
3use lsm_tree::{KvPair, UserKey, UserValue};
4use std::{ops::RangeBounds, sync::MutexGuard};
5
6/// A single-writer (serialized) cross-partition transaction
7///
8/// Use [`WriteTransaction::commit`] to commit changes to the partition(s).
9///
10/// Drop the transaction to rollback changes.
11pub struct WriteTransaction<'a> {
12    _guard: MutexGuard<'a, ()>,
13    inner: InnerWriteTransaction,
14}
15
16impl<'a> WriteTransaction<'a> {
17    pub(crate) fn new(
18        keyspace: TxKeyspace,
19        nonce: SnapshotNonce,
20        guard: MutexGuard<'a, ()>,
21    ) -> Self {
22        Self {
23            _guard: guard,
24            inner: InnerWriteTransaction::new(keyspace, nonce),
25        }
26    }
27
28    /// Sets the durability level.
29    #[must_use]
30    pub fn durability(mut self, mode: Option<PersistMode>) -> Self {
31        self.inner = self.inner.durability(mode);
32        self
33    }
34
35    /// Removes an item and returns its value if it existed.
36    ///
37    /// ```
38    /// # use fjall::{Config, Keyspace, PartitionCreateOptions};
39    /// # use std::sync::Arc;
40    /// #
41    /// # let folder = tempfile::tempdir()?;
42    /// # let keyspace = Config::new(folder).open_transactional()?;
43    /// # let partition = keyspace.open_partition("default", PartitionCreateOptions::default())?;
44    /// partition.insert("a", "abc")?;
45    ///
46    /// let mut tx = keyspace.write_tx();
47    ///
48    /// let taken = tx.take(&partition, "a")?.unwrap();
49    /// assert_eq!(b"abc", &*taken);
50    /// tx.commit()?;
51    ///
52    /// let item = partition.get("a")?;
53    /// assert!(item.is_none());
54    /// #
55    /// # Ok::<(), fjall::Error>(())
56    /// ```
57    ///
58    /// # Errors
59    ///
60    /// Will return `Err` if an IO error occurs.
61    pub fn take<K: Into<UserKey>>(
62        &mut self,
63        partition: &TxPartitionHandle,
64        key: K,
65    ) -> crate::Result<Option<UserValue>> {
66        self.inner.take(partition, key)
67    }
68
69    /// Atomically updates an item and returns the new value.
70    ///
71    /// Returning `None` removes the item if it existed before.
72    ///
73    /// # Examples
74    ///
75    /// ```
76    /// # use fjall::{Config, Keyspace, PartitionCreateOptions, Slice};
77    /// #
78    /// # let folder = tempfile::tempdir()?;
79    /// # let keyspace = Config::new(folder).open_transactional()?;
80    /// # let partition = keyspace.open_partition("default", PartitionCreateOptions::default())?;
81    /// partition.insert("a", "abc")?;
82    ///
83    /// let mut tx = keyspace.write_tx();
84    ///
85    /// let updated = tx.update_fetch(&partition, "a", |_| Some(Slice::from(*b"def")))?.unwrap();
86    /// assert_eq!(b"def", &*updated);
87    /// tx.commit()?;
88    ///
89    /// let item = partition.get("a")?;
90    /// assert_eq!(Some("def".as_bytes().into()), item);
91    /// #
92    /// # Ok::<(), fjall::Error>(())
93    /// ```
94    ///
95    /// ```
96    /// # use fjall::{Config, Keyspace, PartitionCreateOptions};
97    /// # use std::sync::Arc;
98    /// #
99    /// # let folder = tempfile::tempdir()?;
100    /// # let keyspace = Config::new(folder).open_transactional()?;
101    /// # let partition = keyspace.open_partition("default", PartitionCreateOptions::default())?;
102    /// partition.insert("a", "abc")?;
103    ///
104    /// let mut tx = keyspace.write_tx();
105    ///
106    /// let updated = tx.update_fetch(&partition, "a", |_| None)?;
107    /// assert!(updated.is_none());
108    /// tx.commit()?;
109    ///
110    /// let item = partition.get("a")?;
111    /// assert!(item.is_none());
112    /// #
113    /// # Ok::<(), fjall::Error>(())
114    /// ```
115    ///
116    /// # Errors
117    ///
118    /// Will return `Err` if an IO error occurs.
119    pub fn update_fetch<K: Into<UserKey>, F: FnMut(Option<&UserValue>) -> Option<UserValue>>(
120        &mut self,
121        partition: &TxPartitionHandle,
122        key: K,
123        f: F,
124    ) -> crate::Result<Option<UserValue>> {
125        self.inner.update_fetch(partition, key, f)
126    }
127
128    /// Atomically updates an item and returns the previous value.
129    ///
130    /// Returning `None` removes the item if it existed before.
131    ///
132    /// # Examples
133    ///
134    /// ```
135    /// # use fjall::{Config, Keyspace, PartitionCreateOptions, Slice};
136    /// #
137    /// # let folder = tempfile::tempdir()?;
138    /// # let keyspace = Config::new(folder).open_transactional()?;
139    /// # let partition = keyspace.open_partition("default", PartitionCreateOptions::default())?;
140    /// partition.insert("a", "abc")?;
141    ///
142    /// let mut tx = keyspace.write_tx();
143    ///
144    /// let prev = tx.fetch_update(&partition, "a", |_| Some(Slice::from(*b"def")))?.unwrap();
145    /// assert_eq!(b"abc", &*prev);
146    /// tx.commit()?;
147    ///
148    /// let item = partition.get("a")?;
149    /// assert_eq!(Some("def".as_bytes().into()), item);
150    /// #
151    /// # Ok::<(), fjall::Error>(())
152    /// ```
153    ///
154    /// ```
155    /// # use fjall::{Config, Keyspace, PartitionCreateOptions};
156    /// # use std::sync::Arc;
157    /// #
158    /// # let folder = tempfile::tempdir()?;
159    /// # let keyspace = Config::new(folder).open_transactional()?;
160    /// # let partition = keyspace.open_partition("default", PartitionCreateOptions::default())?;
161    /// partition.insert("a", "abc")?;
162    ///
163    /// let mut tx = keyspace.write_tx();
164    ///
165    /// let prev = tx.fetch_update(&partition, "a", |_| None)?.unwrap();
166    /// assert_eq!(b"abc", &*prev);
167    /// tx.commit()?;
168    ///
169    /// let item = partition.get("a")?;
170    /// assert!(item.is_none());
171    /// #
172    /// # Ok::<(), fjall::Error>(())
173    /// ```
174    ///
175    /// # Errors
176    ///
177    /// Will return `Err` if an IO error occurs.
178    pub fn fetch_update<K: Into<UserKey>, F: FnMut(Option<&UserValue>) -> Option<UserValue>>(
179        &mut self,
180        partition: &TxPartitionHandle,
181        key: K,
182        f: F,
183    ) -> crate::Result<Option<UserValue>> {
184        self.inner.fetch_update(partition, key, f)
185    }
186
187    /// Retrieves an item from the transaction's state.
188    ///
189    /// The transaction allows reading your own writes (RYOW).
190    ///
191    /// # Examples
192    ///
193    /// ```
194    /// # use fjall::{Config, Keyspace, PartitionCreateOptions};
195    /// #
196    /// # let folder = tempfile::tempdir()?;
197    /// # let keyspace = Config::new(folder).open_transactional()?;
198    /// # let partition = keyspace.open_partition("default", PartitionCreateOptions::default())?;
199    /// partition.insert("a", "previous_value")?;
200    /// assert_eq!(b"previous_value", &*partition.get("a")?.unwrap());
201    ///
202    /// let mut tx = keyspace.write_tx();
203    /// tx.insert(&partition, "a", "new_value");
204    ///
205    /// // Read-your-own-write
206    /// let item = tx.get(&partition, "a")?;
207    /// assert_eq!(Some("new_value".as_bytes().into()), item);
208    ///
209    /// drop(tx);
210    ///
211    /// // Write was not committed
212    /// assert_eq!(b"previous_value", &*partition.get("a")?.unwrap());
213    /// #
214    /// # Ok::<(), fjall::Error>(())
215    /// ```
216    ///
217    /// # Errors
218    ///
219    /// Will return `Err` if an IO error occurs.
220    pub fn get<K: AsRef<[u8]>>(
221        &self,
222        partition: &TxPartitionHandle,
223        key: K,
224    ) -> crate::Result<Option<UserValue>> {
225        self.inner.get(partition, key)
226    }
227
228    /// Retrieves an item from the transaction's state.
229    ///
230    /// The transaction allows reading your own writes (RYOW).
231    ///
232    /// # Examples
233    ///
234    /// ```
235    /// # use fjall::{Config, Keyspace, PartitionCreateOptions};
236    /// #
237    /// # let folder = tempfile::tempdir()?;
238    /// # let keyspace = Config::new(folder).open_transactional()?;
239    /// # let partition = keyspace.open_partition("default", PartitionCreateOptions::default())?;
240    /// partition.insert("a", "previous_value")?;
241    /// assert_eq!(b"previous_value", &*partition.get("a")?.unwrap());
242    ///
243    /// let mut tx = keyspace.write_tx();
244    /// tx.insert(&partition, "a", "new_value");
245    ///
246    /// // Read-your-own-write
247    /// let len = tx.size_of(&partition, "a")?.unwrap_or_default();
248    /// assert_eq!("new_value".len() as u32, len);
249    ///
250    /// drop(tx);
251    ///
252    /// // Write was not committed
253    /// assert_eq!(b"previous_value", &*partition.get("a")?.unwrap());
254    /// #
255    /// # Ok::<(), fjall::Error>(())
256    /// ```
257    ///
258    /// # Errors
259    ///
260    /// Will return `Err` if an IO error occurs.
261    pub fn size_of<K: AsRef<[u8]>>(
262        &self,
263        partition: &TxPartitionHandle,
264        key: K,
265    ) -> crate::Result<Option<u32>> {
266        self.inner.size_of(partition, key)
267    }
268
269    /// Returns `true` if the transaction's state contains the specified key.
270    ///
271    /// # Examples
272    ///
273    /// ```
274    /// # use fjall::{Config, Keyspace, PartitionCreateOptions};
275    /// #
276    /// # let folder = tempfile::tempdir()?;
277    /// # let keyspace = Config::new(folder).open_transactional()?;
278    /// # let partition = keyspace.open_partition("default", PartitionCreateOptions::default())?;
279    /// partition.insert("a", "my_value")?;
280    /// assert!(keyspace.read_tx().contains_key(&partition, "a")?);
281    ///
282    /// let mut tx = keyspace.write_tx();
283    /// assert!(tx.contains_key(&partition, "a")?);
284    ///
285    /// tx.insert(&partition, "b", "my_value2");
286    /// assert!(tx.contains_key(&partition, "b")?);
287    ///
288    /// // Transaction not committed yet
289    /// assert!(!keyspace.read_tx().contains_key(&partition, "b")?);
290    ///
291    /// tx.commit()?;
292    /// assert!(keyspace.read_tx().contains_key(&partition, "b")?);
293    /// #
294    /// # Ok::<(), fjall::Error>(())
295    /// ```
296    ///
297    /// # Errors
298    ///
299    /// Will return `Err` if an IO error occurs.
300    pub fn contains_key<K: AsRef<[u8]>>(
301        &self,
302        partition: &TxPartitionHandle,
303        key: K,
304    ) -> crate::Result<bool> {
305        self.inner.contains_key(partition, key)
306    }
307
308    /// Returns the first key-value pair in the transaction's state.
309    /// The key in this pair is the minimum key in the transaction's state.
310    ///
311    /// # Examples
312    ///
313    /// ```
314    /// # use fjall::{Config, Keyspace, PartitionCreateOptions};
315    /// #
316    /// # let folder = tempfile::tempdir()?;
317    /// # let keyspace = Config::new(folder).open_transactional()?;
318    /// # let partition = keyspace.open_partition("default", PartitionCreateOptions::default())?;
319    /// #
320    /// let mut tx = keyspace.write_tx();
321    /// tx.insert(&partition, "1", "abc");
322    /// tx.insert(&partition, "3", "abc");
323    /// tx.insert(&partition, "5", "abc");
324    ///
325    /// let (key, _) = tx.first_key_value(&partition)?.expect("item should exist");
326    /// assert_eq!(&*key, "1".as_bytes());
327    ///
328    /// assert!(keyspace.read_tx().first_key_value(&partition)?.is_none());
329    /// #
330    /// # Ok::<(), fjall::Error>(())
331    /// ```
332    ///
333    /// # Errors
334    ///
335    /// Will return `Err` if an IO error occurs.
336    pub fn first_key_value(&self, partition: &TxPartitionHandle) -> crate::Result<Option<KvPair>> {
337        self.inner.first_key_value(partition)
338    }
339
340    /// Returns the last key-value pair in the transaction's state.
341    /// The key in this pair is the maximum key in the transaction's state.
342    ///
343    /// # Examples
344    ///
345    /// ```
346    /// # use fjall::{Config, Keyspace, PartitionCreateOptions};
347    /// #
348    /// # let folder = tempfile::tempdir()?;
349    /// # let keyspace = Config::new(folder).open_transactional()?;
350    /// # let partition = keyspace.open_partition("default", PartitionCreateOptions::default())?;
351    /// #
352    /// let mut tx = keyspace.write_tx();
353    /// tx.insert(&partition, "1", "abc");
354    /// tx.insert(&partition, "3", "abc");
355    /// tx.insert(&partition, "5", "abc");
356    ///
357    /// let (key, _) = tx.last_key_value(&partition)?.expect("item should exist");
358    /// assert_eq!(&*key, "5".as_bytes());
359    ///
360    /// assert!(keyspace.read_tx().last_key_value(&partition)?.is_none());
361    /// #
362    /// # Ok::<(), fjall::Error>(())
363    /// ```
364    ///
365    /// # Errors
366    ///
367    /// Will return `Err` if an IO error occurs.
368    pub fn last_key_value(&self, partition: &TxPartitionHandle) -> crate::Result<Option<KvPair>> {
369        self.inner.last_key_value(partition)
370    }
371
372    /// Scans the entire partition, returning the amount of items.
373    ///
374    /// # Examples
375    ///
376    /// ```
377    /// # use fjall::{Config, Keyspace, PartitionCreateOptions};
378    /// #
379    /// # let folder = tempfile::tempdir()?;
380    /// # let keyspace = Config::new(folder).open_transactional()?;
381    /// # let partition = keyspace.open_partition("default", PartitionCreateOptions::default())?;
382    /// partition.insert("a", "my_value")?;
383    /// partition.insert("b", "my_value2")?;
384    ///
385    /// let mut tx = keyspace.write_tx();
386    /// assert_eq!(2, tx.len(&partition)?);
387    ///
388    /// tx.insert(&partition, "c", "my_value3");
389    ///
390    /// // read-your-own write
391    /// assert_eq!(3, tx.len(&partition)?);
392    ///
393    /// // Transaction is not committed yet
394    /// assert_eq!(2, keyspace.read_tx().len(&partition)?);
395    ///
396    /// tx.commit()?;
397    /// assert_eq!(3, keyspace.read_tx().len(&partition)?);
398    /// #
399    /// # Ok::<(), fjall::Error>(())
400    /// ```
401    ///
402    /// # Errors
403    ///
404    /// Will return `Err` if an IO error occurs.
405    pub fn len(&self, partition: &TxPartitionHandle) -> crate::Result<usize> {
406        self.inner.len(partition)
407    }
408
409    /// Iterates over the transaction's state.
410    ///
411    /// Avoid using this function, or limit it as otherwise it may scan a lot of items.
412    ///
413    /// # Examples
414    ///
415    /// ```
416    /// # use fjall::{Config, Keyspace, PartitionCreateOptions};
417    /// #
418    /// # let folder = tempfile::tempdir()?;
419    /// # let keyspace = Config::new(folder).open_transactional()?;
420    /// # let partition = keyspace.open_partition("default", PartitionCreateOptions::default())?;
421    /// #
422    /// let mut tx = keyspace.write_tx();
423    /// tx.insert(&partition, "a", "abc");
424    /// tx.insert(&partition, "f", "abc");
425    /// tx.insert(&partition, "g", "abc");
426    ///
427    /// assert_eq!(3, tx.iter(&partition).count());
428    /// assert_eq!(0, keyspace.read_tx().iter(&partition).count());
429    /// #
430    /// # Ok::<(), fjall::Error>(())
431    /// ```
432    #[must_use]
433    pub fn iter<'b>(
434        &'b self,
435        partition: &TxPartitionHandle,
436    ) -> impl DoubleEndedIterator<Item = crate::Result<KvPair>> + 'b {
437        self.inner.iter(partition)
438    }
439
440    /// Iterates over the transaction's state, returning keys only.
441    ///
442    /// Avoid using this function, or limit it as otherwise it may scan a lot of items.
443    #[must_use]
444    pub fn keys<'b>(
445        &'b self,
446        partition: &TxPartitionHandle,
447    ) -> impl DoubleEndedIterator<Item = crate::Result<UserKey>> + 'b {
448        self.inner.keys(partition)
449    }
450
451    /// Iterates over the transaction's state, returning values only.
452    ///
453    /// Avoid using this function, or limit it as otherwise it may scan a lot of items.
454    #[must_use]
455    pub fn values<'b>(
456        &'b self,
457        partition: &TxPartitionHandle,
458    ) -> impl DoubleEndedIterator<Item = crate::Result<UserValue>> + 'b {
459        self.inner.values(partition)
460    }
461
462    // Iterates over a range of the transaction's state.
463    ///
464    /// Avoid using full or unbounded ranges as they may scan a lot of items (unless limited).
465    ///
466    /// # Examples
467    ///
468    /// ```
469    /// # use fjall::{Config, Keyspace, PartitionCreateOptions};
470    /// #
471    /// # let folder = tempfile::tempdir()?;
472    /// # let keyspace = Config::new(folder).open_transactional()?;
473    /// # let partition = keyspace.open_partition("default", PartitionCreateOptions::default())?;
474    /// #
475    /// let mut tx = keyspace.write_tx();
476    /// tx.insert(&partition, "a", "abc");
477    /// tx.insert(&partition, "f", "abc");
478    /// tx.insert(&partition, "g", "abc");
479    ///
480    /// assert_eq!(2, tx.range(&partition, "a"..="f").count());
481    /// assert_eq!(0, keyspace.read_tx().range(&partition, "a"..="f").count());
482    /// #
483    /// # Ok::<(), fjall::Error>(())
484    /// ```
485    #[must_use]
486    pub fn range<'b, K: AsRef<[u8]> + 'b, R: RangeBounds<K> + 'b>(
487        &'b self,
488        partition: &'b TxPartitionHandle,
489        range: R,
490    ) -> impl DoubleEndedIterator<Item = crate::Result<KvPair>> + 'b {
491        self.inner.range(partition, range)
492    }
493
494    /// Iterates over a prefixed set of the transaction's state.
495    ///
496    /// Avoid using an empty prefix as it may scan a lot of items (unless limited).
497    ///
498    /// # Examples
499    ///
500    /// ```
501    /// # use fjall::{Config, Keyspace, PartitionCreateOptions};
502    /// #
503    /// # let folder = tempfile::tempdir()?;
504    /// # let keyspace = Config::new(folder).open_transactional()?;
505    /// # let partition = keyspace.open_partition("default", PartitionCreateOptions::default())?;
506    /// #
507    /// let mut tx = keyspace.write_tx();
508    /// tx.insert(&partition, "a", "abc");
509    /// tx.insert(&partition, "ab", "abc");
510    /// tx.insert(&partition, "abc", "abc");
511    ///
512    /// assert_eq!(2, tx.prefix(&partition, "ab").count());
513    /// assert_eq!(0, keyspace.read_tx().prefix(&partition, "ab").count());
514    /// #
515    /// # Ok::<(), fjall::Error>(())
516    /// ```
517    #[must_use]
518    pub fn prefix<'b, K: AsRef<[u8]> + 'b>(
519        &'b self,
520        partition: &'b TxPartitionHandle,
521        prefix: K,
522    ) -> impl DoubleEndedIterator<Item = crate::Result<KvPair>> + 'b {
523        self.inner.prefix(partition, prefix)
524    }
525
526    // Inserts a key-value pair into the partition.
527    ///
528    /// Keys may be up to 65536 bytes long, values up to 2^32 bytes.
529    /// Shorter keys and values result in better performance.
530    ///
531    /// If the key already exists, the item will be overwritten.
532    ///
533    /// # Examples
534    ///
535    /// ```
536    /// # use fjall::{Config, Keyspace, PartitionCreateOptions};
537    /// #
538    /// # let folder = tempfile::tempdir()?;
539    /// # let keyspace = Config::new(folder).open_transactional()?;
540    /// # let partition = keyspace.open_partition("default", PartitionCreateOptions::default())?;
541    /// partition.insert("a", "previous_value")?;
542    /// assert_eq!(b"previous_value", &*partition.get("a")?.unwrap());
543    ///
544    /// let mut tx = keyspace.write_tx();
545    /// tx.insert(&partition, "a", "new_value");
546    ///
547    /// drop(tx);
548    ///
549    /// // Write was not committed
550    /// assert_eq!(b"previous_value", &*partition.get("a")?.unwrap());
551    /// #
552    /// # Ok::<(), fjall::Error>(())
553    /// ```
554    ///
555    /// # Errors
556    ///
557    /// Will return `Err` if an IO error occurs.
558    pub fn insert<K: Into<UserKey>, V: Into<UserValue>>(
559        &mut self,
560        partition: &TxPartitionHandle,
561        key: K,
562        value: V,
563    ) {
564        self.inner.insert(partition, key, value);
565    }
566
567    /// Removes an item from the partition.
568    ///
569    /// The key may be up to 65536 bytes long.
570    /// Shorter keys result in better performance.
571    ///
572    /// # Examples
573    ///
574    /// ```
575    /// # use fjall::{Config, Keyspace, PartitionCreateOptions};
576    /// #
577    /// # let folder = tempfile::tempdir()?;
578    /// # let keyspace = Config::new(folder).open_transactional()?;
579    /// # let partition = keyspace.open_partition("default", PartitionCreateOptions::default())?;
580    /// partition.insert("a", "previous_value")?;
581    /// assert_eq!(b"previous_value", &*partition.get("a")?.unwrap());
582    ///
583    /// let mut tx = keyspace.write_tx();
584    /// tx.remove(&partition, "a");
585    ///
586    /// // Read-your-own-write
587    /// let item = tx.get(&partition, "a")?;
588    /// assert_eq!(None, item);
589    ///
590    /// drop(tx);
591    ///
592    /// // Deletion was not committed
593    /// assert_eq!(b"previous_value", &*partition.get("a")?.unwrap());
594    /// #
595    /// # Ok::<(), fjall::Error>(())
596    /// ```
597    ///
598    /// # Errors
599    ///
600    /// Will return `Err` if an IO error occurs.
601    pub fn remove<K: Into<UserKey>>(&mut self, partition: &TxPartitionHandle, key: K) {
602        self.inner.remove(partition, key);
603    }
604
605    /// Removes an item from the partition, leaving behind a weak tombstone.
606    ///
607    /// The tombstone marker of this delete operation will vanish when it
608    /// collides with its corresponding insertion.
609    /// This may cause older versions of the value to be resurrected, so it should
610    /// only be used and preferred in scenarios where a key is only ever written once.
611    ///
612    /// # Experimental
613    ///
614    /// This function is currently experimental.
615    ///
616    /// # Examples
617    ///
618    /// ```
619    /// # use fjall::{Config, Keyspace, PartitionCreateOptions};
620    /// #
621    /// # let folder = tempfile::tempdir()?;
622    /// # let keyspace = Config::new(folder).open_transactional()?;
623    /// # let partition = keyspace.open_partition("default", PartitionCreateOptions::default())?;
624    /// partition.insert("a", "previous_value")?;
625    /// assert_eq!(b"previous_value", &*partition.get("a")?.unwrap());
626    ///
627    /// let mut tx = keyspace.write_tx();
628    /// tx.remove_weak(&partition, "a");
629    ///
630    /// // Read-your-own-write
631    /// let item = tx.get(&partition, "a")?;
632    /// assert_eq!(None, item);
633    ///
634    /// drop(tx);
635    ///
636    /// // Deletion was not committed
637    /// assert_eq!(b"previous_value", &*partition.get("a")?.unwrap());
638    /// #
639    /// # Ok::<(), fjall::Error>(())
640    /// ```
641    ///
642    /// # Errors
643    ///
644    /// Will return `Err` if an IO error occurs.
645    #[doc(hidden)]
646    pub fn remove_weak<K: Into<UserKey>>(&mut self, partition: &TxPartitionHandle, key: K) {
647        self.inner.remove_weak(partition, key);
648    }
649
650    /// Commits the transaction.
651    ///
652    /// # Errors
653    ///
654    /// Will return `Err` if an IO error occurs.
655    pub fn commit(self) -> crate::Result<()> {
656        self.inner.commit()
657    }
658
659    /// More explicit alternative to dropping the transaction
660    /// to roll it back.
661    pub fn rollback(self) {
662        self.inner.rollback();
663    }
664}