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}