1use std::{
17 collections::BTreeMap,
18 ffi::CString,
19 fs, iter,
20 marker::PhantomData,
21 path::{Path, PathBuf},
22 ptr,
23 sync::{Arc, Mutex},
24};
25
26use crate::CStrLike;
27use std::ffi::CStr;
28
29use crate::column_family::ColumnFamilyTtl;
30use crate::{
31 AsColumnFamilyRef, BoundColumnFamily, ColumnFamily, ColumnFamilyDescriptor, DB,
32 DBIteratorWithThreadMode, DBPinnableSlice, DBRawIteratorWithThreadMode,
33 DEFAULT_COLUMN_FAMILY_NAME, Direction, Error, FlushOptions, IteratorMode, MultiThreaded,
34 Options, ReadOptions, SingleThreaded, SnapshotWithThreadMode, ThreadMode, Transaction,
35 TransactionDBOptions, TransactionOptions, WriteBatchWithTransaction, WriteOptions,
36 column_family::UnboundColumnFamily,
37 db::{DBAccess, convert_values},
38 db_options::OptionsMustOutliveDB,
39 ffi,
40 ffi_util::to_cpath,
41};
42use ffi::rocksdb_transaction_t;
43use libc::{c_char, c_int, c_uchar, c_void, size_t};
44
45thread_local! { static DEFAULT_READ_OPTS: ReadOptions = ReadOptions::default(); }
52thread_local! { static DEFAULT_WRITE_OPTS: WriteOptions = WriteOptions::default(); }
53thread_local! { static DEFAULT_FLUSH_OPTS: FlushOptions = FlushOptions::default(); }
54thread_local! { static DEFAULT_TXN_OPTS: TransactionOptions = TransactionOptions::default(); }
59
60#[cfg(not(feature = "multi-threaded-cf"))]
61type DefaultThreadMode = crate::SingleThreaded;
62#[cfg(feature = "multi-threaded-cf")]
63type DefaultThreadMode = crate::MultiThreaded;
64
65pub struct TransactionDB<T: ThreadMode = DefaultThreadMode> {
106 pub(crate) inner: *mut ffi::rocksdb_transactiondb_t,
107 cfs: T,
108 path: PathBuf,
109 prepared: Mutex<Vec<*mut rocksdb_transaction_t>>,
111 _outlive: Vec<OptionsMustOutliveDB>,
112}
113
114unsafe impl<T: ThreadMode> Send for TransactionDB<T> {}
115unsafe impl<T: ThreadMode> Sync for TransactionDB<T> {}
116
117impl<T: ThreadMode> DBAccess for TransactionDB<T> {
118 unsafe fn create_snapshot(&self) -> *const ffi::rocksdb_snapshot_t {
119 unsafe { ffi::rocksdb_transactiondb_create_snapshot(self.inner) }
120 }
121
122 unsafe fn release_snapshot(&self, snapshot: *const ffi::rocksdb_snapshot_t) {
123 unsafe {
124 ffi::rocksdb_transactiondb_release_snapshot(self.inner, snapshot);
125 }
126 }
127
128 unsafe fn create_iterator(&self, readopts: &ReadOptions) -> *mut ffi::rocksdb_iterator_t {
129 unsafe { ffi::rocksdb_transactiondb_create_iterator(self.inner, readopts.inner) }
130 }
131
132 unsafe fn create_iterator_cf(
133 &self,
134 cf_handle: *mut ffi::rocksdb_column_family_handle_t,
135 readopts: &ReadOptions,
136 ) -> *mut ffi::rocksdb_iterator_t {
137 unsafe {
138 ffi::rocksdb_transactiondb_create_iterator_cf(self.inner, readopts.inner, cf_handle)
139 }
140 }
141
142 fn get_opt<K: AsRef<[u8]>>(
143 &self,
144 key: K,
145 readopts: &ReadOptions,
146 ) -> Result<Option<Vec<u8>>, Error> {
147 self.get_opt(key, readopts)
148 }
149
150 fn get_cf_opt<K: AsRef<[u8]>>(
151 &self,
152 cf: &impl AsColumnFamilyRef,
153 key: K,
154 readopts: &ReadOptions,
155 ) -> Result<Option<Vec<u8>>, Error> {
156 self.get_cf_opt(cf, key, readopts)
157 }
158
159 fn get_pinned_opt<K: AsRef<[u8]>>(
160 &'_ self,
161 key: K,
162 readopts: &ReadOptions,
163 ) -> Result<Option<DBPinnableSlice<'_>>, Error> {
164 self.get_pinned_opt(key, readopts)
165 }
166
167 fn get_pinned_cf_opt<K: AsRef<[u8]>>(
168 &'_ self,
169 cf: &impl AsColumnFamilyRef,
170 key: K,
171 readopts: &ReadOptions,
172 ) -> Result<Option<DBPinnableSlice<'_>>, Error> {
173 self.get_pinned_cf_opt(cf, key, readopts)
174 }
175
176 fn multi_get_opt<K, I>(
177 &self,
178 keys: I,
179 readopts: &ReadOptions,
180 ) -> Vec<Result<Option<Vec<u8>>, Error>>
181 where
182 K: AsRef<[u8]>,
183 I: IntoIterator<Item = K>,
184 {
185 self.multi_get_opt(keys, readopts)
186 }
187
188 fn multi_get_cf_opt<'b, K, I, W>(
189 &self,
190 keys_cf: I,
191 readopts: &ReadOptions,
192 ) -> Vec<Result<Option<Vec<u8>>, Error>>
193 where
194 K: AsRef<[u8]>,
195 I: IntoIterator<Item = (&'b W, K)>,
196 W: AsColumnFamilyRef + 'b,
197 {
198 self.multi_get_cf_opt(keys_cf, readopts)
199 }
200}
201
202impl<T: ThreadMode> TransactionDB<T> {
203 pub fn open_default<P: AsRef<Path>>(path: P) -> Result<Self, Error> {
205 let mut opts = Options::default();
206 opts.create_if_missing(true);
207 let txn_db_opts = TransactionDBOptions::default();
208 Self::open(&opts, &txn_db_opts, path)
209 }
210
211 pub fn open<P: AsRef<Path>>(
213 opts: &Options,
214 txn_db_opts: &TransactionDBOptions,
215 path: P,
216 ) -> Result<Self, Error> {
217 Self::open_cf(opts, txn_db_opts, path, None::<&str>)
218 }
219
220 pub fn open_cf<P, I, N>(
224 opts: &Options,
225 txn_db_opts: &TransactionDBOptions,
226 path: P,
227 cfs: I,
228 ) -> Result<Self, Error>
229 where
230 P: AsRef<Path>,
231 I: IntoIterator<Item = N>,
232 N: AsRef<str>,
233 {
234 let cfs = cfs
235 .into_iter()
236 .map(|name| ColumnFamilyDescriptor::new(name.as_ref(), Options::default()));
237
238 Self::open_cf_descriptors_internal(opts, txn_db_opts, path, cfs)
239 }
240
241 pub fn open_cf_descriptors<P, I>(
243 opts: &Options,
244 txn_db_opts: &TransactionDBOptions,
245 path: P,
246 cfs: I,
247 ) -> Result<Self, Error>
248 where
249 P: AsRef<Path>,
250 I: IntoIterator<Item = ColumnFamilyDescriptor>,
251 {
252 Self::open_cf_descriptors_internal(opts, txn_db_opts, path, cfs)
253 }
254
255 fn open_cf_descriptors_internal<P, I>(
257 opts: &Options,
258 txn_db_opts: &TransactionDBOptions,
259 path: P,
260 cfs: I,
261 ) -> Result<Self, Error>
262 where
263 P: AsRef<Path>,
264 I: IntoIterator<Item = ColumnFamilyDescriptor>,
265 {
266 let cfs: Vec<_> = cfs.into_iter().collect();
267 let outlive = iter::once(opts.outlive.clone())
268 .chain(cfs.iter().map(|cf| cf.options.outlive.clone()))
269 .collect();
270
271 let cpath = to_cpath(&path)?;
272
273 if let Err(e) = fs::create_dir_all(&path) {
274 return Err(Error::new(format!(
275 "Failed to create RocksDB directory: `{e:?}`."
276 )));
277 }
278
279 let db: *mut ffi::rocksdb_transactiondb_t;
280 let mut cf_map = BTreeMap::new();
281
282 if cfs.is_empty() {
283 db = Self::open_raw(opts, txn_db_opts, &cpath)?;
284 } else {
285 let mut cfs_v = cfs;
286 if !cfs_v.iter().any(|cf| cf.name == DEFAULT_COLUMN_FAMILY_NAME) {
288 cfs_v.push(ColumnFamilyDescriptor {
289 name: String::from(DEFAULT_COLUMN_FAMILY_NAME),
290 options: Options::default(),
291 ttl: ColumnFamilyTtl::SameAsDb, });
293 }
294 let c_cfs: Vec<CString> = cfs_v
297 .iter()
298 .map(|cf| CString::new(cf.name.as_bytes()).unwrap())
299 .collect();
300
301 let cfnames: Vec<_> = c_cfs.iter().map(|cf| cf.as_ptr()).collect();
302
303 let mut cfhandles: Vec<_> = cfs_v.iter().map(|_| ptr::null_mut()).collect();
305
306 let cfopts: Vec<_> = cfs_v
307 .iter()
308 .map(|cf| cf.options.inner.cast_const())
309 .collect();
310
311 db = Self::open_cf_raw(
312 opts,
313 txn_db_opts,
314 &cpath,
315 &cfs_v,
316 &cfnames,
317 &cfopts,
318 &mut cfhandles,
319 )?;
320
321 for handle in &cfhandles {
322 if handle.is_null() {
323 return Err(Error::new(
324 "Received null column family handle from DB.".to_owned(),
325 ));
326 }
327 }
328
329 for (cf_desc, inner) in cfs_v.iter().zip(cfhandles) {
330 cf_map.insert(cf_desc.name.clone(), inner);
331 }
332 }
333
334 if db.is_null() {
335 return Err(Error::new("Could not initialize database.".to_owned()));
336 }
337
338 let prepared = unsafe {
339 let mut cnt = 0;
340 let ptr = ffi::rocksdb_transactiondb_get_prepared_transactions(db, &raw mut cnt);
341 let mut vec = vec![std::ptr::null_mut(); cnt];
342 if !ptr.is_null() {
343 std::ptr::copy_nonoverlapping(ptr, vec.as_mut_ptr(), cnt);
344 ffi::rocksdb_free(ptr as *mut c_void);
345 }
346 vec
347 };
348
349 Ok(TransactionDB {
350 inner: db,
351 cfs: T::new_cf_map_internal(cf_map),
352 path: path.as_ref().to_path_buf(),
353 prepared: Mutex::new(prepared),
354 _outlive: outlive,
355 })
356 }
357
358 fn open_raw(
359 opts: &Options,
360 txn_db_opts: &TransactionDBOptions,
361 cpath: &CString,
362 ) -> Result<*mut ffi::rocksdb_transactiondb_t, Error> {
363 unsafe {
364 let db = ffi_try!(ffi::rocksdb_transactiondb_open(
365 opts.inner,
366 txn_db_opts.inner,
367 cpath.as_ptr()
368 ));
369 Ok(db)
370 }
371 }
372
373 fn open_cf_raw(
374 opts: &Options,
375 txn_db_opts: &TransactionDBOptions,
376 cpath: &CString,
377 cfs_v: &[ColumnFamilyDescriptor],
378 cfnames: &[*const c_char],
379 cfopts: &[*const ffi::rocksdb_options_t],
380 cfhandles: &mut [*mut ffi::rocksdb_column_family_handle_t],
381 ) -> Result<*mut ffi::rocksdb_transactiondb_t, Error> {
382 unsafe {
383 let db = ffi_try!(ffi::rocksdb_transactiondb_open_column_families(
384 opts.inner,
385 txn_db_opts.inner,
386 cpath.as_ptr(),
387 cfs_v.len() as c_int,
388 cfnames.as_ptr(),
389 cfopts.as_ptr(),
390 cfhandles.as_mut_ptr(),
391 ));
392 Ok(db)
393 }
394 }
395
396 fn create_inner_cf_handle(
397 &self,
398 name: &str,
399 opts: &Options,
400 ) -> Result<*mut ffi::rocksdb_column_family_handle_t, Error> {
401 let cf_name = CString::new(name.as_bytes()).map_err(|_| {
402 Error::new("Failed to convert path to CString when creating cf".to_owned())
403 })?;
404
405 Ok(unsafe {
406 ffi_try!(ffi::rocksdb_transactiondb_create_column_family(
407 self.inner,
408 opts.inner,
409 cf_name.as_ptr(),
410 ))
411 })
412 }
413
414 pub fn list_cf<P: AsRef<Path>>(opts: &Options, path: P) -> Result<Vec<String>, Error> {
415 DB::list_cf(opts, path)
416 }
417
418 pub fn destroy<P: AsRef<Path>>(opts: &Options, path: P) -> Result<(), Error> {
419 DB::destroy(opts, path)
420 }
421
422 pub fn repair<P: AsRef<Path>>(opts: &Options, path: P) -> Result<(), Error> {
423 DB::repair(opts, path)
424 }
425
426 pub fn path(&self) -> &Path {
427 self.path.as_path()
428 }
429
430 pub fn flush_wal(&self, sync: bool) -> Result<(), Error> {
433 unsafe {
434 ffi_try!(ffi::rocksdb_transactiondb_flush_wal(
435 self.inner,
436 c_uchar::from(sync)
437 ));
438 }
439 Ok(())
440 }
441
442 pub fn flush_opt(&self, flushopts: &FlushOptions) -> Result<(), Error> {
444 unsafe {
445 ffi_try!(ffi::rocksdb_transactiondb_flush(
446 self.inner,
447 flushopts.inner
448 ));
449 }
450 Ok(())
451 }
452
453 pub fn flush(&self) -> Result<(), Error> {
455 DEFAULT_FLUSH_OPTS.with(|opts| self.flush_opt(opts))
456 }
457
458 pub fn flush_cf_opt(
460 &self,
461 cf: &impl AsColumnFamilyRef,
462 flushopts: &FlushOptions,
463 ) -> Result<(), Error> {
464 unsafe {
465 ffi_try!(ffi::rocksdb_transactiondb_flush_cf(
466 self.inner,
467 flushopts.inner,
468 cf.inner()
469 ));
470 }
471 Ok(())
472 }
473
474 pub fn flush_cfs_opt(
480 &self,
481 cfs: &[&impl AsColumnFamilyRef],
482 opts: &FlushOptions,
483 ) -> Result<(), Error> {
484 let mut cfs = cfs.iter().map(|cf| cf.inner()).collect::<Vec<_>>();
485 unsafe {
486 ffi_try!(ffi::rocksdb_transactiondb_flush_cfs(
487 self.inner,
488 opts.inner,
489 cfs.as_mut_ptr(),
490 cfs.len() as c_int,
491 ));
492 }
493 Ok(())
494 }
495
496 pub fn flush_cf(&self, cf: &impl AsColumnFamilyRef) -> Result<(), Error> {
499 DEFAULT_FLUSH_OPTS.with(|opts| self.flush_cf_opt(cf, opts))
500 }
501
502 pub fn transaction(&'_ self) -> Transaction<'_, Self> {
504 DEFAULT_WRITE_OPTS.with(|write_opts| {
505 DEFAULT_TXN_OPTS.with(|txn_opts| self.transaction_opt(write_opts, txn_opts))
506 })
507 }
508
509 pub fn transaction_opt<'a>(
511 &'a self,
512 write_opts: &WriteOptions,
513 txn_opts: &TransactionOptions,
514 ) -> Transaction<'a, Self> {
515 Transaction {
516 inner: unsafe {
517 ffi::rocksdb_transaction_begin(
518 self.inner,
519 write_opts.inner,
520 txn_opts.inner,
521 std::ptr::null_mut(),
522 )
523 },
524 _marker: PhantomData,
525 }
526 }
527
528 pub fn prepared_transactions(&'_ self) -> Vec<Transaction<'_, Self>> {
533 self.prepared
534 .lock()
535 .unwrap()
536 .drain(0..)
537 .map(|inner| Transaction {
538 inner,
539 _marker: PhantomData,
540 })
541 .collect()
542 }
543
544 pub fn get<K: AsRef<[u8]>>(&self, key: K) -> Result<Option<Vec<u8>>, Error> {
546 self.get_pinned(key).map(|x| x.map(|v| v.as_ref().to_vec()))
547 }
548
549 pub fn get_cf<K: AsRef<[u8]>>(
551 &self,
552 cf: &impl AsColumnFamilyRef,
553 key: K,
554 ) -> Result<Option<Vec<u8>>, Error> {
555 self.get_pinned_cf(cf, key)
556 .map(|x| x.map(|v| v.as_ref().to_vec()))
557 }
558
559 pub fn get_opt<K: AsRef<[u8]>>(
561 &self,
562 key: K,
563 readopts: &ReadOptions,
564 ) -> Result<Option<Vec<u8>>, Error> {
565 self.get_pinned_opt(key, readopts)
566 .map(|x| x.map(|v| v.as_ref().to_vec()))
567 }
568
569 pub fn get_cf_opt<K: AsRef<[u8]>>(
571 &self,
572 cf: &impl AsColumnFamilyRef,
573 key: K,
574 readopts: &ReadOptions,
575 ) -> Result<Option<Vec<u8>>, Error> {
576 self.get_pinned_cf_opt(cf, key, readopts)
577 .map(|x| x.map(|v| v.as_ref().to_vec()))
578 }
579
580 pub fn get_pinned<K: AsRef<[u8]>>(
581 &'_ self,
582 key: K,
583 ) -> Result<Option<DBPinnableSlice<'_>>, Error> {
584 DEFAULT_READ_OPTS.with(|opts| self.get_pinned_opt(key, opts))
585 }
586
587 pub fn get_pinned_cf<K: AsRef<[u8]>>(
589 &'_ self,
590 cf: &impl AsColumnFamilyRef,
591 key: K,
592 ) -> Result<Option<DBPinnableSlice<'_>>, Error> {
593 DEFAULT_READ_OPTS.with(|opts| self.get_pinned_cf_opt(cf, key, opts))
594 }
595
596 pub fn get_pinned_opt<K: AsRef<[u8]>>(
598 &'_ self,
599 key: K,
600 readopts: &ReadOptions,
601 ) -> Result<Option<DBPinnableSlice<'_>>, Error> {
602 let key = key.as_ref();
603 unsafe {
604 let val = ffi_try!(ffi::rocksdb_transactiondb_get_pinned(
605 self.inner,
606 readopts.inner,
607 key.as_ptr() as *const c_char,
608 key.len() as size_t,
609 ));
610 if val.is_null() {
611 Ok(None)
612 } else {
613 Ok(Some(DBPinnableSlice::from_c(val)))
614 }
615 }
616 }
617
618 pub fn get_pinned_cf_opt<K: AsRef<[u8]>>(
620 &'_ self,
621 cf: &impl AsColumnFamilyRef,
622 key: K,
623 readopts: &ReadOptions,
624 ) -> Result<Option<DBPinnableSlice<'_>>, Error> {
625 let key = key.as_ref();
626 unsafe {
627 let val = ffi_try!(ffi::rocksdb_transactiondb_get_pinned_cf(
628 self.inner,
629 readopts.inner,
630 cf.inner(),
631 key.as_ptr() as *const c_char,
632 key.len() as size_t,
633 ));
634 if val.is_null() {
635 Ok(None)
636 } else {
637 Ok(Some(DBPinnableSlice::from_c(val)))
638 }
639 }
640 }
641
642 pub fn multi_get<K, I>(&self, keys: I) -> Vec<Result<Option<Vec<u8>>, Error>>
644 where
645 K: AsRef<[u8]>,
646 I: IntoIterator<Item = K>,
647 {
648 DEFAULT_READ_OPTS.with(|opts| self.multi_get_opt(keys, opts))
649 }
650
651 pub fn multi_get_opt<K, I>(
653 &self,
654 keys: I,
655 readopts: &ReadOptions,
656 ) -> Vec<Result<Option<Vec<u8>>, Error>>
657 where
658 K: AsRef<[u8]>,
659 I: IntoIterator<Item = K>,
660 {
661 let owned_keys: Vec<K> = keys.into_iter().collect();
662 let (ptr_keys, keys_sizes): (Vec<*const c_char>, Vec<usize>) = owned_keys
663 .iter()
664 .map(|k| {
665 let key = k.as_ref();
666 (key.as_ptr() as *const c_char, key.len())
667 })
668 .unzip();
669
670 let mut values: Vec<*mut c_char> = Vec::with_capacity(ptr_keys.len());
671 let mut values_sizes: Vec<usize> = Vec::with_capacity(ptr_keys.len());
672 let mut errors: Vec<*mut c_char> = Vec::with_capacity(ptr_keys.len());
673 unsafe {
674 ffi::rocksdb_transactiondb_multi_get(
675 self.inner,
676 readopts.inner,
677 ptr_keys.len(),
678 ptr_keys.as_ptr(),
679 keys_sizes.as_ptr(),
680 values.as_mut_ptr(),
681 values_sizes.as_mut_ptr(),
682 errors.as_mut_ptr(),
683 );
684 }
685
686 unsafe {
687 values.set_len(ptr_keys.len());
688 values_sizes.set_len(ptr_keys.len());
689 errors.set_len(ptr_keys.len());
690 }
691
692 convert_values(values, values_sizes, errors)
693 }
694
695 pub fn multi_get_cf<'a, 'b: 'a, K, I, W>(
697 &'a self,
698 keys: I,
699 ) -> Vec<Result<Option<Vec<u8>>, Error>>
700 where
701 K: AsRef<[u8]>,
702 I: IntoIterator<Item = (&'b W, K)>,
703 W: 'b + AsColumnFamilyRef,
704 {
705 DEFAULT_READ_OPTS.with(|opts| self.multi_get_cf_opt(keys, opts))
706 }
707
708 pub fn multi_get_cf_opt<'a, 'b: 'a, K, I, W>(
710 &'a self,
711 keys: I,
712 readopts: &ReadOptions,
713 ) -> Vec<Result<Option<Vec<u8>>, Error>>
714 where
715 K: AsRef<[u8]>,
716 I: IntoIterator<Item = (&'b W, K)>,
717 W: 'b + AsColumnFamilyRef,
718 {
719 let cfs_and_owned_keys: Vec<(&'b W, K)> = keys.into_iter().collect();
720 let (ptr_keys, keys_sizes): (Vec<*const c_char>, Vec<usize>) = cfs_and_owned_keys
721 .iter()
722 .map(|(_, k)| {
723 let key = k.as_ref();
724 (key.as_ptr() as *const c_char, key.len())
725 })
726 .unzip();
727 let ptr_cfs: Vec<*const ffi::rocksdb_column_family_handle_t> = cfs_and_owned_keys
728 .iter()
729 .map(|(c, _)| c.inner().cast_const())
730 .collect();
731 let mut values: Vec<*mut c_char> = Vec::with_capacity(ptr_keys.len());
732 let mut values_sizes: Vec<usize> = Vec::with_capacity(ptr_keys.len());
733 let mut errors: Vec<*mut c_char> = Vec::with_capacity(ptr_keys.len());
734 unsafe {
735 ffi::rocksdb_transactiondb_multi_get_cf(
736 self.inner,
737 readopts.inner,
738 ptr_cfs.as_ptr(),
739 ptr_keys.len(),
740 ptr_keys.as_ptr(),
741 keys_sizes.as_ptr(),
742 values.as_mut_ptr(),
743 values_sizes.as_mut_ptr(),
744 errors.as_mut_ptr(),
745 );
746 }
747
748 unsafe {
749 values.set_len(ptr_keys.len());
750 values_sizes.set_len(ptr_keys.len());
751 errors.set_len(ptr_keys.len());
752 }
753
754 convert_values(values, values_sizes, errors)
755 }
756
757 pub fn put<K, V>(&self, key: K, value: V) -> Result<(), Error>
758 where
759 K: AsRef<[u8]>,
760 V: AsRef<[u8]>,
761 {
762 DEFAULT_WRITE_OPTS.with(|opts| self.put_opt(key, value, opts))
763 }
764
765 pub fn put_cf<K, V>(&self, cf: &impl AsColumnFamilyRef, key: K, value: V) -> Result<(), Error>
766 where
767 K: AsRef<[u8]>,
768 V: AsRef<[u8]>,
769 {
770 DEFAULT_WRITE_OPTS.with(|opts| self.put_cf_opt(cf, key, value, opts))
771 }
772
773 pub fn put_opt<K, V>(&self, key: K, value: V, writeopts: &WriteOptions) -> Result<(), Error>
774 where
775 K: AsRef<[u8]>,
776 V: AsRef<[u8]>,
777 {
778 let key = key.as_ref();
779 let value = value.as_ref();
780 unsafe {
781 ffi_try!(ffi::rocksdb_transactiondb_put(
782 self.inner,
783 writeopts.inner,
784 key.as_ptr() as *const c_char,
785 key.len() as size_t,
786 value.as_ptr() as *const c_char,
787 value.len() as size_t
788 ));
789 }
790 Ok(())
791 }
792
793 pub fn put_cf_opt<K, V>(
794 &self,
795 cf: &impl AsColumnFamilyRef,
796 key: K,
797 value: V,
798 writeopts: &WriteOptions,
799 ) -> Result<(), Error>
800 where
801 K: AsRef<[u8]>,
802 V: AsRef<[u8]>,
803 {
804 let key = key.as_ref();
805 let value = value.as_ref();
806 unsafe {
807 ffi_try!(ffi::rocksdb_transactiondb_put_cf(
808 self.inner,
809 writeopts.inner,
810 cf.inner(),
811 key.as_ptr() as *const c_char,
812 key.len() as size_t,
813 value.as_ptr() as *const c_char,
814 value.len() as size_t
815 ));
816 }
817 Ok(())
818 }
819
820 pub fn write(&self, batch: &WriteBatchWithTransaction<true>) -> Result<(), Error> {
821 DEFAULT_WRITE_OPTS.with(|opts| self.write_opt(batch, opts))
822 }
823
824 pub fn write_opt(
825 &self,
826 batch: &WriteBatchWithTransaction<true>,
827 writeopts: &WriteOptions,
828 ) -> Result<(), Error> {
829 unsafe {
830 ffi_try!(ffi::rocksdb_transactiondb_write(
831 self.inner,
832 writeopts.inner,
833 batch.inner
834 ));
835 }
836 Ok(())
837 }
838
839 pub fn merge<K, V>(&self, key: K, value: V) -> Result<(), Error>
840 where
841 K: AsRef<[u8]>,
842 V: AsRef<[u8]>,
843 {
844 DEFAULT_WRITE_OPTS.with(|opts| self.merge_opt(key, value, opts))
845 }
846
847 pub fn merge_cf<K, V>(&self, cf: &impl AsColumnFamilyRef, key: K, value: V) -> Result<(), Error>
848 where
849 K: AsRef<[u8]>,
850 V: AsRef<[u8]>,
851 {
852 DEFAULT_WRITE_OPTS.with(|opts| self.merge_cf_opt(cf, key, value, opts))
853 }
854
855 pub fn merge_opt<K, V>(&self, key: K, value: V, writeopts: &WriteOptions) -> Result<(), Error>
856 where
857 K: AsRef<[u8]>,
858 V: AsRef<[u8]>,
859 {
860 let key = key.as_ref();
861 let value = value.as_ref();
862 unsafe {
863 ffi_try!(ffi::rocksdb_transactiondb_merge(
864 self.inner,
865 writeopts.inner,
866 key.as_ptr() as *const c_char,
867 key.len() as size_t,
868 value.as_ptr() as *const c_char,
869 value.len() as size_t,
870 ));
871 Ok(())
872 }
873 }
874
875 pub fn merge_cf_opt<K, V>(
876 &self,
877 cf: &impl AsColumnFamilyRef,
878 key: K,
879 value: V,
880 writeopts: &WriteOptions,
881 ) -> Result<(), Error>
882 where
883 K: AsRef<[u8]>,
884 V: AsRef<[u8]>,
885 {
886 let key = key.as_ref();
887 let value = value.as_ref();
888 unsafe {
889 ffi_try!(ffi::rocksdb_transactiondb_merge_cf(
890 self.inner,
891 writeopts.inner,
892 cf.inner(),
893 key.as_ptr() as *const c_char,
894 key.len() as size_t,
895 value.as_ptr() as *const c_char,
896 value.len() as size_t,
897 ));
898 Ok(())
899 }
900 }
901
902 pub fn delete<K: AsRef<[u8]>>(&self, key: K) -> Result<(), Error> {
903 DEFAULT_WRITE_OPTS.with(|opts| self.delete_opt(key, opts))
904 }
905
906 pub fn delete_cf<K: AsRef<[u8]>>(
907 &self,
908 cf: &impl AsColumnFamilyRef,
909 key: K,
910 ) -> Result<(), Error> {
911 DEFAULT_WRITE_OPTS.with(|opts| self.delete_cf_opt(cf, key, opts))
912 }
913
914 pub fn delete_opt<K: AsRef<[u8]>>(
915 &self,
916 key: K,
917 writeopts: &WriteOptions,
918 ) -> Result<(), Error> {
919 let key = key.as_ref();
920 unsafe {
921 ffi_try!(ffi::rocksdb_transactiondb_delete(
922 self.inner,
923 writeopts.inner,
924 key.as_ptr() as *const c_char,
925 key.len() as size_t,
926 ));
927 }
928 Ok(())
929 }
930
931 pub fn delete_cf_opt<K: AsRef<[u8]>>(
932 &self,
933 cf: &impl AsColumnFamilyRef,
934 key: K,
935 writeopts: &WriteOptions,
936 ) -> Result<(), Error> {
937 let key = key.as_ref();
938 unsafe {
939 ffi_try!(ffi::rocksdb_transactiondb_delete_cf(
940 self.inner,
941 writeopts.inner,
942 cf.inner(),
943 key.as_ptr() as *const c_char,
944 key.len() as size_t,
945 ));
946 }
947 Ok(())
948 }
949
950 pub fn iterator<'a: 'b, 'b>(
951 &'a self,
952 mode: IteratorMode,
953 ) -> DBIteratorWithThreadMode<'b, Self> {
954 let readopts = ReadOptions::default();
955 self.iterator_opt(mode, readopts)
956 }
957
958 pub fn iterator_opt<'a: 'b, 'b>(
959 &'a self,
960 mode: IteratorMode,
961 readopts: ReadOptions,
962 ) -> DBIteratorWithThreadMode<'b, Self> {
963 DBIteratorWithThreadMode::new(self, readopts, mode)
964 }
965
966 pub fn iterator_cf_opt<'a: 'b, 'b>(
969 &'a self,
970 cf_handle: &impl AsColumnFamilyRef,
971 readopts: ReadOptions,
972 mode: IteratorMode,
973 ) -> DBIteratorWithThreadMode<'b, Self> {
974 DBIteratorWithThreadMode::new_cf(self, cf_handle.inner(), readopts, mode)
975 }
976
977 pub fn full_iterator<'a: 'b, 'b>(
981 &'a self,
982 mode: IteratorMode,
983 ) -> DBIteratorWithThreadMode<'b, Self> {
984 let mut opts = ReadOptions::default();
985 opts.set_total_order_seek(true);
986 DBIteratorWithThreadMode::new(self, opts, mode)
987 }
988
989 pub fn prefix_iterator<'a: 'b, 'b, P: AsRef<[u8]>>(
990 &'a self,
991 prefix: P,
992 ) -> DBIteratorWithThreadMode<'b, Self> {
993 let mut opts = ReadOptions::default();
994 opts.set_prefix_same_as_start(true);
995 DBIteratorWithThreadMode::new(
996 self,
997 opts,
998 IteratorMode::From(prefix.as_ref(), Direction::Forward),
999 )
1000 }
1001
1002 pub fn iterator_cf<'a: 'b, 'b>(
1003 &'a self,
1004 cf_handle: &impl AsColumnFamilyRef,
1005 mode: IteratorMode,
1006 ) -> DBIteratorWithThreadMode<'b, Self> {
1007 let opts = ReadOptions::default();
1008 DBIteratorWithThreadMode::new_cf(self, cf_handle.inner(), opts, mode)
1009 }
1010
1011 pub fn full_iterator_cf<'a: 'b, 'b>(
1012 &'a self,
1013 cf_handle: &impl AsColumnFamilyRef,
1014 mode: IteratorMode,
1015 ) -> DBIteratorWithThreadMode<'b, Self> {
1016 let mut opts = ReadOptions::default();
1017 opts.set_total_order_seek(true);
1018 DBIteratorWithThreadMode::new_cf(self, cf_handle.inner(), opts, mode)
1019 }
1020
1021 pub fn prefix_iterator_cf<'a, P: AsRef<[u8]>>(
1022 &'a self,
1023 cf_handle: &impl AsColumnFamilyRef,
1024 prefix: P,
1025 ) -> DBIteratorWithThreadMode<'a, Self> {
1026 let mut opts = ReadOptions::default();
1027 opts.set_prefix_same_as_start(true);
1028 DBIteratorWithThreadMode::<'a, Self>::new_cf(
1029 self,
1030 cf_handle.inner(),
1031 opts,
1032 IteratorMode::From(prefix.as_ref(), Direction::Forward),
1033 )
1034 }
1035
1036 pub fn raw_iterator<'a: 'b, 'b>(&'a self) -> DBRawIteratorWithThreadMode<'b, Self> {
1038 let opts = ReadOptions::default();
1039 DBRawIteratorWithThreadMode::new(self, opts)
1040 }
1041
1042 pub fn raw_iterator_cf<'a: 'b, 'b>(
1044 &'a self,
1045 cf_handle: &impl AsColumnFamilyRef,
1046 ) -> DBRawIteratorWithThreadMode<'b, Self> {
1047 let opts = ReadOptions::default();
1048 DBRawIteratorWithThreadMode::new_cf(self, cf_handle.inner(), opts)
1049 }
1050
1051 pub fn raw_iterator_opt<'a: 'b, 'b>(
1053 &'a self,
1054 readopts: ReadOptions,
1055 ) -> DBRawIteratorWithThreadMode<'b, Self> {
1056 DBRawIteratorWithThreadMode::new(self, readopts)
1057 }
1058
1059 pub fn raw_iterator_cf_opt<'a: 'b, 'b>(
1061 &'a self,
1062 cf_handle: &impl AsColumnFamilyRef,
1063 readopts: ReadOptions,
1064 ) -> DBRawIteratorWithThreadMode<'b, Self> {
1065 DBRawIteratorWithThreadMode::new_cf(self, cf_handle.inner(), readopts)
1066 }
1067
1068 pub fn snapshot(&'_ self) -> SnapshotWithThreadMode<'_, Self> {
1069 SnapshotWithThreadMode::<Self>::new(self)
1070 }
1071
1072 fn mark_column_family_dropped(
1083 &self,
1084 cf_inner: *mut ffi::rocksdb_column_family_handle_t,
1085 ) -> Result<(), Error> {
1086 unsafe {
1087 ffi_try!(ffi::rocksdb_drop_column_family(
1088 self.inner as *mut ffi::rocksdb_t,
1089 cf_inner
1090 ));
1091 }
1092 Ok(())
1093 }
1094}
1095
1096impl TransactionDB<SingleThreaded> {
1097 pub fn create_cf<N: AsRef<str>>(&mut self, name: N, opts: &Options) -> Result<(), Error> {
1099 let inner = self.create_inner_cf_handle(name.as_ref(), opts)?;
1100 self.cfs
1101 .cfs
1102 .insert(name.as_ref().to_string(), ColumnFamily { inner });
1103 Ok(())
1104 }
1105
1106 pub fn cf_handle(&self, name: &str) -> Option<&ColumnFamily> {
1108 self.cfs.cfs.get(name)
1109 }
1110
1111 pub fn drop_cf(&mut self, name: &str) -> Result<(), Error> {
1113 let Some(cf) = self.cfs.cfs.remove(name) else {
1114 return Err(Error::new(format!("Invalid column family: {name}")));
1115 };
1116 match self.mark_column_family_dropped(cf.inner) {
1117 Ok(()) => Ok(()),
1122 Err(e) => {
1123 self.cfs.cfs.insert(name.to_owned(), cf);
1126 Err(e)
1127 }
1128 }
1129 }
1130}
1131
1132impl TransactionDB<MultiThreaded> {
1133 pub fn create_cf<N: AsRef<str>>(&self, name: N, opts: &Options) -> Result<(), Error> {
1135 let mut cfs = self.cfs.cfs.write();
1138 let inner = self.create_inner_cf_handle(name.as_ref(), opts)?;
1139 cfs.insert(
1140 name.as_ref().to_string(),
1141 Arc::new(UnboundColumnFamily { inner }),
1142 );
1143 Ok(())
1144 }
1145
1146 pub fn cf_handle(&'_ self, name: &str) -> Option<Arc<BoundColumnFamily<'_>>> {
1148 self.cfs
1149 .cfs
1150 .read()
1151 .get(name)
1152 .cloned()
1153 .map(UnboundColumnFamily::bound_column_family)
1154 }
1155
1156 pub fn drop_cf(&self, name: &str) -> Result<(), Error> {
1159 let Some(cf) = self.cfs.cfs.write().remove(name) else {
1165 return Err(Error::new(format!("Invalid column family: {name}")));
1166 };
1167 match self.mark_column_family_dropped(cf.inner) {
1168 Ok(()) => Ok(()),
1173 Err(e) => {
1174 self.cfs.cfs.write().insert(name.to_owned(), cf);
1177 Err(e)
1178 }
1179 }
1180 }
1181
1182 fn property_value_impl<R>(
1191 name: impl CStrLike,
1192 get_property: impl FnOnce(*const c_char) -> *mut c_char,
1193 parse: impl FnOnce(&str) -> Result<R, Error>,
1194 ) -> Result<Option<R>, Error> {
1195 let value = match name.bake() {
1196 Ok(prop_name) => get_property(prop_name.as_ptr()),
1197 Err(e) => {
1198 return Err(Error::new(format!(
1199 "Failed to convert property name to CString: {e}"
1200 )));
1201 }
1202 };
1203 if value.is_null() {
1204 return Ok(None);
1205 }
1206 let result = match unsafe { CStr::from_ptr(value) }.to_str() {
1207 Ok(s) => parse(s).map(|value| Some(value)),
1208 Err(e) => Err(Error::new(format!(
1209 "Failed to convert property value to string: {e}"
1210 ))),
1211 };
1212 unsafe {
1213 ffi::rocksdb_free(value as *mut c_void);
1214 }
1215 result
1216 }
1217
1218 pub fn property_value(&self, name: impl CStrLike) -> Result<Option<String>, Error> {
1223 Self::property_value_impl(
1224 name,
1225 |prop_name| unsafe { ffi::rocksdb_transactiondb_property_value(self.inner, prop_name) },
1226 |str_value| Ok(str_value.to_owned()),
1227 )
1228 }
1229
1230 fn property_int_value_impl(
1231 name: impl CStrLike,
1232 get_property: impl FnOnce(*const c_char, *mut u64) -> c_int,
1233 get_string_property: impl FnOnce(*const c_char) -> *mut c_char,
1234 ) -> Result<Option<u64>, Error> {
1235 let prop_name = name.bake().map_err(|err| {
1236 Error::new(format!("Failed to convert property name to CString: {err}"))
1237 })?;
1238 let mut value = 0;
1239 if get_property(prop_name.as_ptr(), &raw mut value) == 0 {
1240 return Ok(Some(value));
1241 }
1242
1243 Self::property_value_impl(
1244 prop_name.as_ref(),
1245 get_string_property,
1246 Self::parse_property_int_value,
1247 )
1248 }
1249
1250 fn parse_property_int_value(value: &str) -> Result<u64, Error> {
1251 value.parse::<u64>().map_err(|err| {
1252 Error::new(format!(
1253 "Failed to convert property value {value} to int: {err}"
1254 ))
1255 })
1256 }
1257
1258 pub fn property_int_value(&self, name: impl CStrLike) -> Result<Option<u64>, Error> {
1263 Self::property_int_value_impl(
1264 name,
1265 |prop_name, value| unsafe {
1266 ffi::rocksdb_transactiondb_property_int(self.inner, prop_name, value)
1267 },
1268 |prop_name| unsafe { ffi::rocksdb_transactiondb_property_value(self.inner, prop_name) },
1269 )
1270 }
1271}
1272
1273impl<T: ThreadMode> Drop for TransactionDB<T> {
1274 fn drop(&mut self) {
1275 unsafe {
1276 self.prepared_transactions().clear();
1277 self.cfs.drop_all_cfs_internal();
1278 ffi::rocksdb_transactiondb_close(self.inner);
1279 }
1280 }
1281}