1use std::cell::RefCell;
17use std::collections::{BTreeMap, HashMap};
18use std::ffi::{CStr, CString};
19use std::fmt;
20use std::fs;
21use std::iter;
22use std::path::Path;
23use std::path::PathBuf;
24use std::ptr;
25use std::slice;
26use std::str;
27use std::sync::Arc;
28use std::time::Duration;
29
30use crate::column_family::ColumnFamilyTtl;
31use crate::ffi_util::CSlice;
32use crate::{
33 ColumnFamily, ColumnFamilyDescriptor, CompactOptions, DBIteratorWithThreadMode,
34 DBPinnableBatch, DBPinnableSlice, DBRawIteratorWithThreadMode, DBWALIterator,
35 DEFAULT_COLUMN_FAMILY_NAME, Direction, Error, FlushOptions, IngestExternalFileOptions,
36 IteratorMode, Options, ReadOptions, SnapshotWithThreadMode, WaitForCompactOptions, WriteBatch,
37 WriteBatchWithIndex, WriteOptions,
38 column_family::{AsColumnFamilyRef, BoundColumnFamily, UnboundColumnFamily},
39 db_options::{ImportColumnFamilyOptions, OptionsMustOutliveDB},
40 ffi,
41 ffi_util::{
42 CStrLike, convert_rocksdb_error, from_cstr_and_free, from_cstr_without_free,
43 opt_bytes_to_ptr, raw_data, to_cpath,
44 },
45};
46use rust_librocksdb_sys::{
47 rocksdb_livefile_destroy, rocksdb_livefile_t, rocksdb_livefiles_destroy, rocksdb_livefiles_t,
48};
49
50use libc::{self, c_char, c_int, c_uchar, c_void, size_t};
51use parking_lot::RwLock;
52
53thread_local! { static DEFAULT_READ_OPTS: ReadOptions = ReadOptions::default(); }
60thread_local! { static DEFAULT_WRITE_OPTS: WriteOptions = WriteOptions::default(); }
61thread_local! { static DEFAULT_FLUSH_OPTS: FlushOptions = FlushOptions::default(); }
62thread_local! { static PREFIX_READ_OPTS: RefCell<ReadOptions> = RefCell::new({ let mut o = ReadOptions::default(); o.set_prefix_same_as_start(true); o }); }
64
65fn with_prefix_read_opts<R>(prefix: &[u8], f: impl FnOnce(&ReadOptions) -> R) -> R {
76 PREFIX_READ_OPTS.with(|rc| {
77 if let Ok(mut opts) = rc.try_borrow_mut() {
78 opts.set_prefix_range_in_place(prefix);
79 f(&opts)
80 } else {
81 let mut opts = ReadOptions::default();
82 opts.set_prefix_same_as_start(true);
83 opts.set_prefix_range_in_place(prefix);
84 f(&opts)
85 }
86 })
87}
88
89pub struct Range<'a> {
93 start_key: &'a [u8],
94 end_key: &'a [u8],
95}
96
97impl<'a> Range<'a> {
98 pub fn new(start_key: &'a [u8], end_key: &'a [u8]) -> Range<'a> {
99 Range { start_key, end_key }
100 }
101}
102
103#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
142pub enum GetIntoBufferResult {
143 NotFound,
145 Found(usize),
148 BufferTooSmall(usize),
154}
155
156impl GetIntoBufferResult {
157 #[inline]
159 pub fn is_found(&self) -> bool {
160 matches!(self, Self::Found(_) | Self::BufferTooSmall(_))
161 }
162
163 #[inline]
165 pub fn is_not_found(&self) -> bool {
166 matches!(self, Self::NotFound)
167 }
168
169 #[inline]
171 pub fn value_size(&self) -> Option<usize> {
172 match self {
173 Self::Found(size) | Self::BufferTooSmall(size) => Some(*size),
174 Self::NotFound => None,
175 }
176 }
177}
178
179pub struct PrefixProber<'a, D: DBAccess> {
183 raw: DBRawIteratorWithThreadMode<'a, D>,
184}
185
186impl<D: DBAccess> PrefixProber<'_, D> {
187 pub fn exists(&mut self, prefix: &[u8]) -> Result<bool, Error> {
190 self.raw.seek(prefix);
191 if self.raw.valid()
192 && let Some(k) = self.raw.key()
193 {
194 return Ok(k.starts_with(prefix));
195 }
196 self.raw.status()?;
197 Ok(false)
198 }
199}
200
201pub trait ThreadMode {
212 fn new_cf_map_internal(
214 cf_map: BTreeMap<String, *mut ffi::rocksdb_column_family_handle_t>,
215 ) -> Self;
216 fn drop_all_cfs_internal(&mut self);
218}
219
220pub struct SingleThreaded {
227 pub(crate) cfs: HashMap<String, ColumnFamily>,
228}
229
230pub struct MultiThreaded {
236 pub(crate) cfs: RwLock<HashMap<String, Arc<UnboundColumnFamily>>>,
237}
238
239impl ThreadMode for SingleThreaded {
240 fn new_cf_map_internal(
241 cfs: BTreeMap<String, *mut ffi::rocksdb_column_family_handle_t>,
242 ) -> Self {
243 Self {
244 cfs: cfs
245 .into_iter()
246 .map(|(n, c)| (n, ColumnFamily { inner: c }))
247 .collect(),
248 }
249 }
250
251 fn drop_all_cfs_internal(&mut self) {
252 self.cfs.clear();
254 }
255}
256
257impl ThreadMode for MultiThreaded {
258 fn new_cf_map_internal(
259 cfs: BTreeMap<String, *mut ffi::rocksdb_column_family_handle_t>,
260 ) -> Self {
261 Self {
262 cfs: RwLock::new(
263 cfs.into_iter()
264 .map(|(n, c)| (n, Arc::new(UnboundColumnFamily { inner: c })))
265 .collect(),
266 ),
267 }
268 }
269
270 fn drop_all_cfs_internal(&mut self) {
271 self.cfs.write().clear();
273 }
274}
275
276pub trait DBInner {
278 fn inner(&self) -> *mut ffi::rocksdb_t;
279}
280
281pub struct DBCommon<T: ThreadMode, D: DBInner> {
302 pub(crate) inner: D,
303 cfs: T, path: PathBuf,
305 _outlive: Vec<OptionsMustOutliveDB>,
306}
307
308pub trait DBAccess {
311 unsafe fn create_snapshot(&self) -> *const ffi::rocksdb_snapshot_t;
312
313 unsafe fn release_snapshot(&self, snapshot: *const ffi::rocksdb_snapshot_t);
314
315 unsafe fn create_iterator(&self, readopts: &ReadOptions) -> *mut ffi::rocksdb_iterator_t;
316
317 unsafe fn create_iterator_cf(
318 &self,
319 cf_handle: *mut ffi::rocksdb_column_family_handle_t,
320 readopts: &ReadOptions,
321 ) -> *mut ffi::rocksdb_iterator_t;
322
323 fn get_opt<K: AsRef<[u8]>>(
324 &self,
325 key: K,
326 readopts: &ReadOptions,
327 ) -> Result<Option<Vec<u8>>, Error>;
328
329 fn get_cf_opt<K: AsRef<[u8]>>(
330 &self,
331 cf: &impl AsColumnFamilyRef,
332 key: K,
333 readopts: &ReadOptions,
334 ) -> Result<Option<Vec<u8>>, Error>;
335
336 fn get_pinned_opt<K: AsRef<[u8]>>(
337 &'_ self,
338 key: K,
339 readopts: &ReadOptions,
340 ) -> Result<Option<DBPinnableSlice<'_>>, Error>;
341
342 fn get_pinned_cf_opt<K: AsRef<[u8]>>(
343 &'_ self,
344 cf: &impl AsColumnFamilyRef,
345 key: K,
346 readopts: &ReadOptions,
347 ) -> Result<Option<DBPinnableSlice<'_>>, Error>;
348
349 fn multi_get_opt<K, I>(
350 &self,
351 keys: I,
352 readopts: &ReadOptions,
353 ) -> Vec<Result<Option<Vec<u8>>, Error>>
354 where
355 K: AsRef<[u8]>,
356 I: IntoIterator<Item = K>;
357
358 fn multi_get_cf_opt<'b, K, I, W>(
359 &self,
360 keys_cf: I,
361 readopts: &ReadOptions,
362 ) -> Vec<Result<Option<Vec<u8>>, Error>>
363 where
364 K: AsRef<[u8]>,
365 I: IntoIterator<Item = (&'b W, K)>,
366 W: AsColumnFamilyRef + 'b;
367}
368
369impl<T: ThreadMode, D: DBInner> DBAccess for DBCommon<T, D> {
370 unsafe fn create_snapshot(&self) -> *const ffi::rocksdb_snapshot_t {
371 unsafe { ffi::rocksdb_create_snapshot(self.inner.inner()) }
372 }
373
374 unsafe fn release_snapshot(&self, snapshot: *const ffi::rocksdb_snapshot_t) {
375 unsafe {
376 ffi::rocksdb_release_snapshot(self.inner.inner(), snapshot);
377 }
378 }
379
380 unsafe fn create_iterator(&self, readopts: &ReadOptions) -> *mut ffi::rocksdb_iterator_t {
381 unsafe { ffi::rocksdb_create_iterator(self.inner.inner(), readopts.inner) }
382 }
383
384 unsafe fn create_iterator_cf(
385 &self,
386 cf_handle: *mut ffi::rocksdb_column_family_handle_t,
387 readopts: &ReadOptions,
388 ) -> *mut ffi::rocksdb_iterator_t {
389 unsafe { ffi::rocksdb_create_iterator_cf(self.inner.inner(), readopts.inner, cf_handle) }
390 }
391
392 fn get_opt<K: AsRef<[u8]>>(
393 &self,
394 key: K,
395 readopts: &ReadOptions,
396 ) -> Result<Option<Vec<u8>>, Error> {
397 self.get_opt(key, readopts)
398 }
399
400 fn get_cf_opt<K: AsRef<[u8]>>(
401 &self,
402 cf: &impl AsColumnFamilyRef,
403 key: K,
404 readopts: &ReadOptions,
405 ) -> Result<Option<Vec<u8>>, Error> {
406 self.get_cf_opt(cf, key, readopts)
407 }
408
409 fn get_pinned_opt<K: AsRef<[u8]>>(
410 &'_ self,
411 key: K,
412 readopts: &ReadOptions,
413 ) -> Result<Option<DBPinnableSlice<'_>>, Error> {
414 self.get_pinned_opt(key, readopts)
415 }
416
417 fn get_pinned_cf_opt<K: AsRef<[u8]>>(
418 &'_ self,
419 cf: &impl AsColumnFamilyRef,
420 key: K,
421 readopts: &ReadOptions,
422 ) -> Result<Option<DBPinnableSlice<'_>>, Error> {
423 self.get_pinned_cf_opt(cf, key, readopts)
424 }
425
426 fn multi_get_opt<K, Iter>(
427 &self,
428 keys: Iter,
429 readopts: &ReadOptions,
430 ) -> Vec<Result<Option<Vec<u8>>, Error>>
431 where
432 K: AsRef<[u8]>,
433 Iter: IntoIterator<Item = K>,
434 {
435 self.multi_get_opt(keys, readopts)
436 }
437
438 fn multi_get_cf_opt<'b, K, Iter, W>(
439 &self,
440 keys_cf: Iter,
441 readopts: &ReadOptions,
442 ) -> Vec<Result<Option<Vec<u8>>, Error>>
443 where
444 K: AsRef<[u8]>,
445 Iter: IntoIterator<Item = (&'b W, K)>,
446 W: AsColumnFamilyRef + 'b,
447 {
448 self.multi_get_cf_opt(keys_cf, readopts)
449 }
450}
451
452pub struct DBWithThreadModeInner {
453 inner: *mut ffi::rocksdb_t,
454}
455
456struct OwnedColumnFamilyHandle {
457 inner: *mut ffi::rocksdb_column_family_handle_t,
458}
459
460struct PinnedMultiGetOutput {
461 values: Vec<*mut ffi::rocksdb_pinnableslice_t>,
462 errors: Vec<*mut c_char>,
463}
464
465struct CreatedIterators {
469 readopts: Arc<ReadOptions>,
470 handles: Vec<*mut ffi::rocksdb_iterator_t>,
471}
472
473impl OwnedColumnFamilyHandle {
474 fn default_for(db: *mut ffi::rocksdb_t) -> Self {
475 Self {
476 inner: unsafe { ffi::rocksdb_get_default_column_family_handle(db) },
477 }
478 }
479}
480
481impl Drop for OwnedColumnFamilyHandle {
482 fn drop(&mut self) {
483 unsafe {
484 ffi::rocksdb_column_family_handle_destroy(self.inner);
485 }
486 }
487}
488
489impl DBInner for DBWithThreadModeInner {
490 #[inline]
491 fn inner(&self) -> *mut ffi::rocksdb_t {
492 self.inner
493 }
494}
495
496impl Drop for DBWithThreadModeInner {
497 fn drop(&mut self) {
498 unsafe {
499 ffi::rocksdb_close(self.inner);
500 }
501 }
502}
503
504pub type DBWithThreadMode<T> = DBCommon<T, DBWithThreadModeInner>;
509
510#[cfg(not(feature = "multi-threaded-cf"))]
533pub type DB = DBWithThreadMode<SingleThreaded>;
534
535#[cfg(feature = "multi-threaded-cf")]
536pub type DB = DBWithThreadMode<MultiThreaded>;
537
538unsafe impl<T: ThreadMode + Send, I: DBInner> Send for DBCommon<T, I> {}
542
543unsafe impl<T: ThreadMode, I: DBInner> Sync for DBCommon<T, I> {}
546
547enum AccessType<'a> {
549 ReadWrite,
550 ReadOnly { error_if_log_file_exist: bool },
551 Secondary { secondary_path: &'a Path },
552 WithTTL { ttl: Duration },
553}
554
555impl<T: ThreadMode> DBWithThreadMode<T> {
557 pub fn open_default<P: AsRef<Path>>(path: P) -> Result<Self, Error> {
559 let mut opts = Options::default();
560 opts.create_if_missing(true);
561 Self::open(&opts, path)
562 }
563
564 pub fn open<P: AsRef<Path>>(opts: &Options, path: P) -> Result<Self, Error> {
566 Self::open_cf(opts, path, None::<&str>)
567 }
568
569 pub fn open_for_read_only<P: AsRef<Path>>(
571 opts: &Options,
572 path: P,
573 error_if_log_file_exist: bool,
574 ) -> Result<Self, Error> {
575 Self::open_cf_for_read_only(opts, path, None::<&str>, error_if_log_file_exist)
576 }
577
578 pub fn open_as_secondary<P: AsRef<Path>>(
580 opts: &Options,
581 primary_path: P,
582 secondary_path: P,
583 ) -> Result<Self, Error> {
584 Self::open_cf_as_secondary(opts, primary_path, secondary_path, None::<&str>)
585 }
586
587 pub fn open_with_ttl<P: AsRef<Path>>(
596 opts: &Options,
597 path: P,
598 ttl: Duration,
599 ) -> Result<Self, Error> {
600 Self::open_cf_descriptors_with_ttl(opts, path, std::iter::empty(), ttl)
601 }
602
603 pub fn open_cf_with_ttl<P, I, N>(
607 opts: &Options,
608 path: P,
609 cfs: I,
610 ttl: Duration,
611 ) -> Result<Self, Error>
612 where
613 P: AsRef<Path>,
614 I: IntoIterator<Item = N>,
615 N: AsRef<str>,
616 {
617 let cfs = cfs
618 .into_iter()
619 .map(|name| ColumnFamilyDescriptor::new(name.as_ref(), Options::default()));
620
621 Self::open_cf_descriptors_with_ttl(opts, path, cfs, ttl)
622 }
623
624 pub fn open_cf_descriptors_with_ttl<P, I>(
638 opts: &Options,
639 path: P,
640 cfs: I,
641 ttl: Duration,
642 ) -> Result<Self, Error>
643 where
644 P: AsRef<Path>,
645 I: IntoIterator<Item = ColumnFamilyDescriptor>,
646 {
647 Self::open_cf_descriptors_internal(opts, path, cfs, &AccessType::WithTTL { ttl })
648 }
649
650 pub fn open_cf<P, I, N>(opts: &Options, path: P, cfs: I) -> Result<Self, Error>
654 where
655 P: AsRef<Path>,
656 I: IntoIterator<Item = N>,
657 N: AsRef<str>,
658 {
659 let cfs = cfs
660 .into_iter()
661 .map(|name| ColumnFamilyDescriptor::new(name.as_ref(), Options::default()));
662
663 Self::open_cf_descriptors_internal(opts, path, cfs, &AccessType::ReadWrite)
664 }
665
666 pub fn open_cf_with_opts<P, I, N>(opts: &Options, path: P, cfs: I) -> Result<Self, Error>
670 where
671 P: AsRef<Path>,
672 I: IntoIterator<Item = (N, Options)>,
673 N: AsRef<str>,
674 {
675 let cfs = cfs
676 .into_iter()
677 .map(|(name, opts)| ColumnFamilyDescriptor::new(name.as_ref(), opts));
678
679 Self::open_cf_descriptors(opts, path, cfs)
680 }
681
682 pub fn open_cf_for_read_only<P, I, N>(
686 opts: &Options,
687 path: P,
688 cfs: I,
689 error_if_log_file_exist: bool,
690 ) -> Result<Self, Error>
691 where
692 P: AsRef<Path>,
693 I: IntoIterator<Item = N>,
694 N: AsRef<str>,
695 {
696 let cfs = cfs
697 .into_iter()
698 .map(|name| ColumnFamilyDescriptor::new(name.as_ref(), Options::default()));
699
700 Self::open_cf_descriptors_internal(
701 opts,
702 path,
703 cfs,
704 &AccessType::ReadOnly {
705 error_if_log_file_exist,
706 },
707 )
708 }
709
710 pub fn open_cf_with_opts_for_read_only<P, I, N>(
714 db_opts: &Options,
715 path: P,
716 cfs: I,
717 error_if_log_file_exist: bool,
718 ) -> Result<Self, Error>
719 where
720 P: AsRef<Path>,
721 I: IntoIterator<Item = (N, Options)>,
722 N: AsRef<str>,
723 {
724 let cfs = cfs
725 .into_iter()
726 .map(|(name, cf_opts)| ColumnFamilyDescriptor::new(name.as_ref(), cf_opts));
727
728 Self::open_cf_descriptors_internal(
729 db_opts,
730 path,
731 cfs,
732 &AccessType::ReadOnly {
733 error_if_log_file_exist,
734 },
735 )
736 }
737
738 pub fn open_cf_descriptors_read_only<P, I>(
743 opts: &Options,
744 path: P,
745 cfs: I,
746 error_if_log_file_exist: bool,
747 ) -> Result<Self, Error>
748 where
749 P: AsRef<Path>,
750 I: IntoIterator<Item = ColumnFamilyDescriptor>,
751 {
752 Self::open_cf_descriptors_internal(
753 opts,
754 path,
755 cfs,
756 &AccessType::ReadOnly {
757 error_if_log_file_exist,
758 },
759 )
760 }
761
762 pub fn open_cf_as_secondary<P, I, N>(
766 opts: &Options,
767 primary_path: P,
768 secondary_path: P,
769 cfs: I,
770 ) -> Result<Self, Error>
771 where
772 P: AsRef<Path>,
773 I: IntoIterator<Item = N>,
774 N: AsRef<str>,
775 {
776 let cfs = cfs
777 .into_iter()
778 .map(|name| ColumnFamilyDescriptor::new(name.as_ref(), Options::default()));
779
780 Self::open_cf_descriptors_internal(
781 opts,
782 primary_path,
783 cfs,
784 &AccessType::Secondary {
785 secondary_path: secondary_path.as_ref(),
786 },
787 )
788 }
789
790 pub fn open_cf_descriptors_as_secondary<P, I>(
795 opts: &Options,
796 path: P,
797 secondary_path: P,
798 cfs: I,
799 ) -> Result<Self, Error>
800 where
801 P: AsRef<Path>,
802 I: IntoIterator<Item = ColumnFamilyDescriptor>,
803 {
804 Self::open_cf_descriptors_internal(
805 opts,
806 path,
807 cfs,
808 &AccessType::Secondary {
809 secondary_path: secondary_path.as_ref(),
810 },
811 )
812 }
813
814 pub fn open_cf_descriptors<P, I>(opts: &Options, path: P, cfs: I) -> Result<Self, Error>
818 where
819 P: AsRef<Path>,
820 I: IntoIterator<Item = ColumnFamilyDescriptor>,
821 {
822 Self::open_cf_descriptors_internal(opts, path, cfs, &AccessType::ReadWrite)
823 }
824
825 fn open_cf_descriptors_internal<P, I>(
827 opts: &Options,
828 path: P,
829 cfs: I,
830 access_type: &AccessType,
831 ) -> Result<Self, Error>
832 where
833 P: AsRef<Path>,
834 I: IntoIterator<Item = ColumnFamilyDescriptor>,
835 {
836 let cfs: Vec<_> = cfs.into_iter().collect();
837 let outlive = iter::once(opts.outlive.clone())
838 .chain(cfs.iter().map(|cf| cf.options.outlive.clone()))
839 .collect();
840
841 let cpath = to_cpath(&path)?;
842
843 if let Err(e) = fs::create_dir_all(&path) {
844 return Err(Error::new(format!(
845 "Failed to create RocksDB directory: `{e:?}`."
846 )));
847 }
848
849 let db: *mut ffi::rocksdb_t;
850 let mut cf_map = BTreeMap::new();
851
852 if cfs.is_empty() {
853 db = Self::open_raw(opts, &cpath, access_type)?;
854 } else {
855 let mut cfs_v = cfs;
856 if !cfs_v.iter().any(|cf| cf.name == DEFAULT_COLUMN_FAMILY_NAME) {
858 cfs_v.push(ColumnFamilyDescriptor {
859 name: String::from(DEFAULT_COLUMN_FAMILY_NAME),
860 options: Options::default(),
861 ttl: ColumnFamilyTtl::SameAsDb,
862 });
863 }
864 let c_cfs: Vec<CString> = cfs_v
867 .iter()
868 .map(|cf| CString::new(cf.name.as_bytes()).unwrap())
869 .collect();
870
871 let cfnames: Vec<_> = c_cfs.iter().map(|cf| cf.as_ptr()).collect();
872
873 let mut cfhandles: Vec<_> = cfs_v.iter().map(|_| ptr::null_mut()).collect();
875
876 let cfopts: Vec<_> = cfs_v
877 .iter()
878 .map(|cf| cf.options.inner.cast_const())
879 .collect();
880
881 db = Self::open_cf_raw(
882 opts,
883 &cpath,
884 &cfs_v,
885 &cfnames,
886 &cfopts,
887 &mut cfhandles,
888 access_type,
889 )?;
890 for handle in &cfhandles {
891 if handle.is_null() {
892 return Err(Error::new(
893 "Received null column family handle from DB.".to_owned(),
894 ));
895 }
896 }
897
898 for (cf_desc, inner) in cfs_v.iter().zip(cfhandles) {
899 cf_map.insert(cf_desc.name.clone(), inner);
900 }
901 }
902
903 if db.is_null() {
904 return Err(Error::new("Could not initialize database.".to_owned()));
905 }
906
907 Ok(Self {
908 inner: DBWithThreadModeInner { inner: db },
909 path: path.as_ref().to_path_buf(),
910 cfs: T::new_cf_map_internal(cf_map),
911 _outlive: outlive,
912 })
913 }
914
915 fn open_raw(
916 opts: &Options,
917 cpath: &CString,
918 access_type: &AccessType,
919 ) -> Result<*mut ffi::rocksdb_t, Error> {
920 let db = unsafe {
921 match *access_type {
922 AccessType::ReadOnly {
923 error_if_log_file_exist,
924 } => ffi_try!(ffi::rocksdb_open_for_read_only(
925 opts.inner,
926 cpath.as_ptr(),
927 c_uchar::from(error_if_log_file_exist),
928 )),
929 AccessType::ReadWrite => {
930 ffi_try!(ffi::rocksdb_open(opts.inner, cpath.as_ptr()))
931 }
932 AccessType::Secondary { secondary_path } => {
933 ffi_try!(ffi::rocksdb_open_as_secondary(
934 opts.inner,
935 cpath.as_ptr(),
936 to_cpath(secondary_path)?.as_ptr(),
937 ))
938 }
939 AccessType::WithTTL { ttl } => ffi_try!(ffi::rocksdb_open_with_ttl(
940 opts.inner,
941 cpath.as_ptr(),
942 ttl_to_seconds(ttl),
943 )),
944 }
945 };
946 Ok(db)
947 }
948
949 #[allow(clippy::pedantic)]
950 fn open_cf_raw(
951 opts: &Options,
952 cpath: &CString,
953 cfs_v: &[ColumnFamilyDescriptor],
954 cfnames: &[*const c_char],
955 cfopts: &[*const ffi::rocksdb_options_t],
956 cfhandles: &mut [*mut ffi::rocksdb_column_family_handle_t],
957 access_type: &AccessType,
958 ) -> Result<*mut ffi::rocksdb_t, Error> {
959 let db = unsafe {
960 match *access_type {
961 AccessType::ReadOnly {
962 error_if_log_file_exist,
963 } => ffi_try!(ffi::rocksdb_open_for_read_only_column_families(
964 opts.inner,
965 cpath.as_ptr(),
966 cfs_v.len() as c_int,
967 cfnames.as_ptr(),
968 cfopts.as_ptr(),
969 cfhandles.as_mut_ptr(),
970 c_uchar::from(error_if_log_file_exist),
971 )),
972 AccessType::ReadWrite => ffi_try!(ffi::rocksdb_open_column_families(
973 opts.inner,
974 cpath.as_ptr(),
975 cfs_v.len() as c_int,
976 cfnames.as_ptr(),
977 cfopts.as_ptr(),
978 cfhandles.as_mut_ptr(),
979 )),
980 AccessType::Secondary { secondary_path } => {
981 ffi_try!(ffi::rocksdb_open_as_secondary_column_families(
982 opts.inner,
983 cpath.as_ptr(),
984 to_cpath(secondary_path)?.as_ptr(),
985 cfs_v.len() as c_int,
986 cfnames.as_ptr(),
987 cfopts.as_ptr(),
988 cfhandles.as_mut_ptr(),
989 ))
990 }
991 AccessType::WithTTL { ttl } => {
992 let ttls: Vec<_> = cfs_v
993 .iter()
994 .map(|cf| match cf.ttl {
995 ColumnFamilyTtl::Disabled => i32::MAX,
996 ColumnFamilyTtl::Duration(duration) => ttl_to_seconds(duration),
997 ColumnFamilyTtl::SameAsDb => ttl_to_seconds(ttl),
998 })
999 .collect();
1000
1001 ffi_try!(ffi::rocksdb_open_column_families_with_ttl(
1002 opts.inner,
1003 cpath.as_ptr(),
1004 cfs_v.len() as c_int,
1005 cfnames.as_ptr(),
1006 cfopts.as_ptr(),
1007 cfhandles.as_mut_ptr(),
1008 ttls.as_ptr(),
1009 ))
1010 }
1011 }
1012 };
1013 Ok(db)
1014 }
1015
1016 pub fn delete_range_cf_opt<K: AsRef<[u8]>>(
1018 &self,
1019 cf: &impl AsColumnFamilyRef,
1020 from: K,
1021 to: K,
1022 writeopts: &WriteOptions,
1023 ) -> Result<(), Error> {
1024 let from = from.as_ref();
1025 let to = to.as_ref();
1026
1027 unsafe {
1028 ffi_try!(ffi::rocksdb_delete_range_cf(
1029 self.inner.inner(),
1030 writeopts.inner,
1031 cf.inner(),
1032 from.as_ptr() as *const c_char,
1033 from.len() as size_t,
1034 to.as_ptr() as *const c_char,
1035 to.len() as size_t,
1036 ));
1037 Ok(())
1038 }
1039 }
1040
1041 pub fn delete_range_cf<K: AsRef<[u8]>>(
1043 &self,
1044 cf: &impl AsColumnFamilyRef,
1045 from: K,
1046 to: K,
1047 ) -> Result<(), Error> {
1048 DEFAULT_WRITE_OPTS.with(|opts| self.delete_range_cf_opt(cf, from, to, opts))
1049 }
1050
1051 pub fn write_opt(&self, batch: &WriteBatch, writeopts: &WriteOptions) -> Result<(), Error> {
1052 unsafe {
1053 ffi_try!(ffi::rocksdb_write(
1054 self.inner.inner(),
1055 writeopts.inner,
1056 batch.inner
1057 ));
1058 }
1059 Ok(())
1060 }
1061
1062 pub fn write(&self, batch: &WriteBatch) -> Result<(), Error> {
1063 DEFAULT_WRITE_OPTS.with(|opts| self.write_opt(batch, opts))
1064 }
1065
1066 pub fn write_without_wal(&self, batch: &WriteBatch) -> Result<(), Error> {
1067 let mut wo = WriteOptions::new();
1068 wo.disable_wal(true);
1069 self.write_opt(batch, &wo)
1070 }
1071
1072 pub fn write_wbwi(&self, wbwi: &WriteBatchWithIndex) -> Result<(), Error> {
1073 DEFAULT_WRITE_OPTS.with(|opts| self.write_wbwi_opt(wbwi, opts))
1074 }
1075
1076 pub fn write_wbwi_opt(
1077 &self,
1078 wbwi: &WriteBatchWithIndex,
1079 writeopts: &WriteOptions,
1080 ) -> Result<(), Error> {
1081 unsafe {
1082 ffi_try!(ffi::rocksdb_write_writebatch_wi(
1083 self.inner.inner(),
1084 writeopts.inner,
1085 wbwi.inner
1086 ));
1087
1088 Ok(())
1089 }
1090 }
1091}
1092
1093impl<T: ThreadMode, D: DBInner> DBCommon<T, D> {
1095 pub(crate) fn new(inner: D, cfs: T, path: PathBuf, outlive: Vec<OptionsMustOutliveDB>) -> Self {
1096 Self {
1097 inner,
1098 cfs,
1099 path,
1100 _outlive: outlive,
1101 }
1102 }
1103
1104 pub fn list_cf<P: AsRef<Path>>(opts: &Options, path: P) -> Result<Vec<String>, Error> {
1105 let cpath = to_cpath(path)?;
1106 let mut length = 0;
1107
1108 unsafe {
1109 let ptr = ffi_try!(ffi::rocksdb_list_column_families(
1110 opts.inner,
1111 cpath.as_ptr(),
1112 &raw mut length,
1113 ));
1114
1115 let vec = slice::from_raw_parts(ptr, length)
1116 .iter()
1117 .map(|ptr| from_cstr_without_free(*ptr))
1118 .collect();
1119 ffi::rocksdb_list_column_families_destroy(ptr, length);
1120 Ok(vec)
1121 }
1122 }
1123
1124 pub fn destroy<P: AsRef<Path>>(opts: &Options, path: P) -> Result<(), Error> {
1125 let cpath = to_cpath(path)?;
1126 unsafe {
1127 ffi_try!(ffi::rocksdb_destroy_db(opts.inner, cpath.as_ptr()));
1128 }
1129 Ok(())
1130 }
1131
1132 pub fn repair<P: AsRef<Path>>(opts: &Options, path: P) -> Result<(), Error> {
1133 let cpath = to_cpath(path)?;
1134 unsafe {
1135 ffi_try!(ffi::rocksdb_repair_db(opts.inner, cpath.as_ptr()));
1136 }
1137 Ok(())
1138 }
1139
1140 pub fn path(&self) -> &Path {
1141 self.path.as_path()
1142 }
1143
1144 pub fn flush_wal(&self, sync: bool) -> Result<(), Error> {
1147 unsafe {
1148 ffi_try!(ffi::rocksdb_flush_wal(
1149 self.inner.inner(),
1150 c_uchar::from(sync)
1151 ));
1152 }
1153 Ok(())
1154 }
1155
1156 pub fn disable_file_deletions(&self) -> Result<(), Error> {
1161 unsafe {
1162 ffi_try!(ffi::rocksdb_disable_file_deletions(self.inner.inner()));
1163 }
1164 Ok(())
1165 }
1166
1167 pub fn enable_file_deletions(&self) -> Result<(), Error> {
1179 unsafe {
1180 ffi_try!(ffi::rocksdb_enable_file_deletions(self.inner.inner()));
1181 }
1182 Ok(())
1183 }
1184
1185 pub fn flush_opt(&self, flushopts: &FlushOptions) -> Result<(), Error> {
1187 unsafe {
1188 ffi_try!(ffi::rocksdb_flush(self.inner.inner(), flushopts.inner));
1189 }
1190 Ok(())
1191 }
1192
1193 pub fn flush(&self) -> Result<(), Error> {
1195 DEFAULT_FLUSH_OPTS.with(|opts| self.flush_opt(opts))
1196 }
1197
1198 pub fn flush_cf_opt(
1200 &self,
1201 cf: &impl AsColumnFamilyRef,
1202 flushopts: &FlushOptions,
1203 ) -> Result<(), Error> {
1204 unsafe {
1205 ffi_try!(ffi::rocksdb_flush_cf(
1206 self.inner.inner(),
1207 flushopts.inner,
1208 cf.inner()
1209 ));
1210 }
1211 Ok(())
1212 }
1213
1214 pub fn flush_cfs_opt(
1220 &self,
1221 cfs: &[&impl AsColumnFamilyRef],
1222 opts: &FlushOptions,
1223 ) -> Result<(), Error> {
1224 let mut cfs = cfs.iter().map(|cf| cf.inner()).collect::<Vec<_>>();
1225 unsafe {
1226 ffi_try!(ffi::rocksdb_flush_cfs(
1227 self.inner.inner(),
1228 opts.inner,
1229 cfs.as_mut_ptr(),
1230 cfs.len() as libc::c_int,
1231 ));
1232 }
1233 Ok(())
1234 }
1235
1236 pub fn flush_cf(&self, cf: &impl AsColumnFamilyRef) -> Result<(), Error> {
1239 DEFAULT_FLUSH_OPTS.with(|opts| self.flush_cf_opt(cf, opts))
1240 }
1241
1242 pub fn get_opt<K: AsRef<[u8]>>(
1246 &self,
1247 key: K,
1248 readopts: &ReadOptions,
1249 ) -> Result<Option<Vec<u8>>, Error> {
1250 self.get_pinned_opt(key, readopts)
1251 .map(|x| x.map(|v| v.as_ref().to_vec()))
1252 }
1253
1254 pub fn get<K: AsRef<[u8]>>(&self, key: K) -> Result<Option<Vec<u8>>, Error> {
1258 DEFAULT_READ_OPTS.with(|opts| self.get_opt(key.as_ref(), opts))
1259 }
1260
1261 pub fn get_cf_opt<K: AsRef<[u8]>>(
1265 &self,
1266 cf: &impl AsColumnFamilyRef,
1267 key: K,
1268 readopts: &ReadOptions,
1269 ) -> Result<Option<Vec<u8>>, Error> {
1270 self.get_pinned_cf_opt(cf, key, readopts)
1271 .map(|x| x.map(|v| v.as_ref().to_vec()))
1272 }
1273
1274 pub fn get_cf<K: AsRef<[u8]>>(
1278 &self,
1279 cf: &impl AsColumnFamilyRef,
1280 key: K,
1281 ) -> Result<Option<Vec<u8>>, Error> {
1282 DEFAULT_READ_OPTS.with(|opts| self.get_cf_opt(cf, key.as_ref(), opts))
1283 }
1284
1285 pub fn get_pinned_opt<K: AsRef<[u8]>>(
1288 &'_ self,
1289 key: K,
1290 readopts: &ReadOptions,
1291 ) -> Result<Option<DBPinnableSlice<'_>>, Error> {
1292 if readopts.inner.is_null() {
1293 return Err(Error::new(
1294 "Unable to create RocksDB read options. This is a fairly trivial call, and its \
1295 failure may be indicative of a mis-compiled or mis-loaded RocksDB library."
1296 .to_owned(),
1297 ));
1298 }
1299
1300 let key = key.as_ref();
1301 unsafe {
1302 let val = ffi_try!(ffi::rocksdb_get_pinned(
1303 self.inner.inner(),
1304 readopts.inner,
1305 key.as_ptr() as *const c_char,
1306 key.len() as size_t,
1307 ));
1308 if val.is_null() {
1309 Ok(None)
1310 } else {
1311 Ok(Some(DBPinnableSlice::from_c(val)))
1312 }
1313 }
1314 }
1315
1316 pub fn get_pinned<K: AsRef<[u8]>>(
1320 &'_ self,
1321 key: K,
1322 ) -> Result<Option<DBPinnableSlice<'_>>, Error> {
1323 DEFAULT_READ_OPTS.with(|opts| self.get_pinned_opt(key, opts))
1324 }
1325
1326 pub fn get_pinned_cf_opt<K: AsRef<[u8]>>(
1330 &'_ self,
1331 cf: &impl AsColumnFamilyRef,
1332 key: K,
1333 readopts: &ReadOptions,
1334 ) -> Result<Option<DBPinnableSlice<'_>>, Error> {
1335 if readopts.inner.is_null() {
1336 return Err(Error::new(
1337 "Unable to create RocksDB read options. This is a fairly trivial call, and its \
1338 failure may be indicative of a mis-compiled or mis-loaded RocksDB library."
1339 .to_owned(),
1340 ));
1341 }
1342
1343 let key = key.as_ref();
1344 unsafe {
1345 let val = ffi_try!(ffi::rocksdb_get_pinned_cf(
1346 self.inner.inner(),
1347 readopts.inner,
1348 cf.inner(),
1349 key.as_ptr() as *const c_char,
1350 key.len() as size_t,
1351 ));
1352 if val.is_null() {
1353 Ok(None)
1354 } else {
1355 Ok(Some(DBPinnableSlice::from_c(val)))
1356 }
1357 }
1358 }
1359
1360 pub fn get_pinned_cf<K: AsRef<[u8]>>(
1364 &'_ self,
1365 cf: &impl AsColumnFamilyRef,
1366 key: K,
1367 ) -> Result<Option<DBPinnableSlice<'_>>, Error> {
1368 DEFAULT_READ_OPTS.with(|opts| self.get_pinned_cf_opt(cf, key, opts))
1369 }
1370
1371 pub fn get_into_buffer<K: AsRef<[u8]>>(
1441 &self,
1442 key: K,
1443 buffer: &mut [u8],
1444 ) -> Result<GetIntoBufferResult, Error> {
1445 DEFAULT_READ_OPTS.with(|opts| self.get_into_buffer_opt(key, buffer, opts))
1446 }
1447
1448 pub fn get_into_buffer_opt<K: AsRef<[u8]>>(
1455 &self,
1456 key: K,
1457 buffer: &mut [u8],
1458 readopts: &ReadOptions,
1459 ) -> Result<GetIntoBufferResult, Error> {
1460 if readopts.inner.is_null() {
1461 return Err(Error::new(
1462 "Unable to create RocksDB read options. This is a fairly trivial call, and its \
1463 failure may be indicative of a mis-compiled or mis-loaded RocksDB library."
1464 .to_owned(),
1465 ));
1466 }
1467
1468 let key = key.as_ref();
1469 let mut val_len: size_t = 0;
1470 let mut found: c_uchar = 0;
1471
1472 unsafe {
1473 let success = ffi_try!(ffi::rocksdb_get_into_buffer(
1474 self.inner.inner(),
1475 readopts.inner,
1476 key.as_ptr() as *const c_char,
1477 key.len() as size_t,
1478 buffer.as_mut_ptr() as *mut c_char,
1479 buffer.len() as size_t,
1480 &raw mut val_len,
1481 &raw mut found,
1482 ));
1483
1484 if found == 0 {
1485 Ok(GetIntoBufferResult::NotFound)
1486 } else if success != 0 {
1487 Ok(GetIntoBufferResult::Found(val_len))
1488 } else {
1489 Ok(GetIntoBufferResult::BufferTooSmall(val_len))
1490 }
1491 }
1492 }
1493
1494 pub fn get_into_buffer_cf<K: AsRef<[u8]>>(
1505 &self,
1506 cf: &impl AsColumnFamilyRef,
1507 key: K,
1508 buffer: &mut [u8],
1509 ) -> Result<GetIntoBufferResult, Error> {
1510 DEFAULT_READ_OPTS.with(|opts| self.get_into_buffer_cf_opt(cf, key, buffer, opts))
1511 }
1512
1513 pub fn get_into_buffer_cf_opt<K: AsRef<[u8]>>(
1519 &self,
1520 cf: &impl AsColumnFamilyRef,
1521 key: K,
1522 buffer: &mut [u8],
1523 readopts: &ReadOptions,
1524 ) -> Result<GetIntoBufferResult, Error> {
1525 if readopts.inner.is_null() {
1526 return Err(Error::new(
1527 "Unable to create RocksDB read options. This is a fairly trivial call, and its \
1528 failure may be indicative of a mis-compiled or mis-loaded RocksDB library."
1529 .to_owned(),
1530 ));
1531 }
1532
1533 let key = key.as_ref();
1534 let mut val_len: size_t = 0;
1535 let mut found: c_uchar = 0;
1536
1537 unsafe {
1538 let success = ffi_try!(ffi::rocksdb_get_into_buffer_cf(
1539 self.inner.inner(),
1540 readopts.inner,
1541 cf.inner(),
1542 key.as_ptr() as *const c_char,
1543 key.len() as size_t,
1544 buffer.as_mut_ptr() as *mut c_char,
1545 buffer.len() as size_t,
1546 &raw mut val_len,
1547 &raw mut found,
1548 ));
1549
1550 if found == 0 {
1551 Ok(GetIntoBufferResult::NotFound)
1552 } else if success != 0 {
1553 Ok(GetIntoBufferResult::Found(val_len))
1554 } else {
1555 Ok(GetIntoBufferResult::BufferTooSmall(val_len))
1556 }
1557 }
1558 }
1559
1560 pub fn multi_get<K, I>(&self, keys: I) -> Vec<Result<Option<Vec<u8>>, Error>>
1562 where
1563 K: AsRef<[u8]>,
1564 I: IntoIterator<Item = K>,
1565 {
1566 DEFAULT_READ_OPTS.with(|opts| self.multi_get_opt(keys, opts))
1567 }
1568
1569 pub fn multi_get_opt<K, I>(
1571 &self,
1572 keys: I,
1573 readopts: &ReadOptions,
1574 ) -> Vec<Result<Option<Vec<u8>>, Error>>
1575 where
1576 K: AsRef<[u8]>,
1577 I: IntoIterator<Item = K>,
1578 {
1579 let owned_keys: Vec<K> = keys.into_iter().collect();
1580 let (ptr_keys, keys_sizes): (Vec<*const c_char>, Vec<usize>) = owned_keys
1581 .iter()
1582 .map(|k| {
1583 let key = k.as_ref();
1584 (key.as_ptr() as *const c_char, key.len())
1585 })
1586 .unzip();
1587
1588 let mut values: Vec<*mut c_char> = Vec::with_capacity(ptr_keys.len());
1589 let mut values_sizes: Vec<usize> = Vec::with_capacity(ptr_keys.len());
1590 let mut errors: Vec<*mut c_char> = Vec::with_capacity(ptr_keys.len());
1591 unsafe {
1592 ffi::rocksdb_multi_get(
1593 self.inner.inner(),
1594 readopts.inner,
1595 ptr_keys.len(),
1596 ptr_keys.as_ptr(),
1597 keys_sizes.as_ptr(),
1598 values.as_mut_ptr(),
1599 values_sizes.as_mut_ptr(),
1600 errors.as_mut_ptr(),
1601 );
1602 }
1603
1604 unsafe {
1605 values.set_len(ptr_keys.len());
1606 values_sizes.set_len(ptr_keys.len());
1607 errors.set_len(ptr_keys.len());
1608 }
1609
1610 convert_values(values, values_sizes, errors)
1611 }
1612
1613 pub fn multi_get_pinned<K, I>(
1617 &'_ self,
1618 keys: I,
1619 ) -> Vec<Result<Option<DBPinnableSlice<'_>>, Error>>
1620 where
1621 K: AsRef<[u8]>,
1622 I: IntoIterator<Item = K>,
1623 {
1624 DEFAULT_READ_OPTS.with(|opts| self.multi_get_pinned_opt(keys, opts))
1625 }
1626
1627 pub fn multi_get_pinned_opt<K, I>(
1631 &'_ self,
1632 keys: I,
1633 readopts: &ReadOptions,
1634 ) -> Vec<Result<Option<DBPinnableSlice<'_>>, Error>>
1635 where
1636 K: AsRef<[u8]>,
1637 I: IntoIterator<Item = K>,
1638 {
1639 let mut keys = keys.into_iter();
1640 let Some(first) = keys.next() else {
1641 return Vec::new();
1642 };
1643 let Some(second) = keys.next() else {
1647 return vec![self.get_pinned_opt(first.as_ref(), readopts)];
1648 };
1649 let mut owned_keys = Vec::with_capacity(2 + keys.size_hint().0);
1650 owned_keys.push(first);
1651 owned_keys.push(second);
1652 owned_keys.extend(keys);
1653 self.batched_multi_get_pinned_owned(&owned_keys, false, readopts)
1654 }
1655
1656 pub fn multi_get_pinned_cf<'a, 'b: 'a, K, I, W>(
1659 &'a self,
1660 keys: I,
1661 ) -> Vec<Result<Option<DBPinnableSlice<'a>>, Error>>
1662 where
1663 K: AsRef<[u8]>,
1664 I: IntoIterator<Item = (&'b W, K)>,
1665 W: 'b + AsColumnFamilyRef,
1666 {
1667 DEFAULT_READ_OPTS.with(|opts| self.multi_get_pinned_cf_opt(keys, opts))
1668 }
1669
1670 pub fn multi_get_pinned_cf_opt<'a, 'b: 'a, K, I, W>(
1673 &'a self,
1674 keys: I,
1675 readopts: &ReadOptions,
1676 ) -> Vec<Result<Option<DBPinnableSlice<'a>>, Error>>
1677 where
1678 K: AsRef<[u8]>,
1679 I: IntoIterator<Item = (&'b W, K)>,
1680 W: 'b + AsColumnFamilyRef,
1681 {
1682 keys.into_iter()
1683 .map(|(cf, k)| self.get_pinned_cf_opt(cf, k, readopts))
1684 .collect()
1685 }
1686
1687 pub fn batched_multi_get_pinned<K, I>(
1692 &'_ self,
1693 keys: I,
1694 sorted_input: bool,
1695 ) -> Vec<Result<Option<DBPinnableSlice<'_>>, Error>>
1696 where
1697 K: AsRef<[u8]>,
1698 I: IntoIterator<Item = K>,
1699 {
1700 DEFAULT_READ_OPTS.with(|opts| self.batched_multi_get_pinned_opt(keys, sorted_input, opts))
1701 }
1702
1703 pub fn batched_multi_get_pinned_opt<K, I>(
1706 &'_ self,
1707 keys: I,
1708 sorted_input: bool,
1709 readopts: &ReadOptions,
1710 ) -> Vec<Result<Option<DBPinnableSlice<'_>>, Error>>
1711 where
1712 K: AsRef<[u8]>,
1713 I: IntoIterator<Item = K>,
1714 {
1715 let owned_keys: Vec<K> = keys.into_iter().collect();
1716 self.batched_multi_get_pinned_owned(&owned_keys, sorted_input, readopts)
1717 }
1718
1719 pub fn batched_multi_get_pinned_cf<K, I>(
1724 &'_ self,
1725 cf: &impl AsColumnFamilyRef,
1726 keys: I,
1727 sorted_input: bool,
1728 ) -> Vec<Result<Option<DBPinnableSlice<'_>>, Error>>
1729 where
1730 K: AsRef<[u8]>,
1731 I: IntoIterator<Item = K>,
1732 {
1733 DEFAULT_READ_OPTS
1734 .with(|opts| self.batched_multi_get_pinned_cf_opt(cf, keys, sorted_input, opts))
1735 }
1736
1737 pub fn batched_multi_get_pinned_cf_opt<K, I>(
1740 &'_ self,
1741 cf: &impl AsColumnFamilyRef,
1742 keys: I,
1743 sorted_input: bool,
1744 readopts: &ReadOptions,
1745 ) -> Vec<Result<Option<DBPinnableSlice<'_>>, Error>>
1746 where
1747 K: AsRef<[u8]>,
1748 I: IntoIterator<Item = K>,
1749 {
1750 let owned_keys: Vec<K> = keys.into_iter().collect();
1751 let key_slices = Self::key_slices(&owned_keys);
1752 self.batched_multi_get_pinned_inner(cf.inner(), &key_slices, sorted_input, readopts)
1753 }
1754
1755 pub fn batched_multi_get_pinned_batch<K, I>(
1760 &'_ self,
1761 keys: I,
1762 sorted_input: bool,
1763 ) -> Result<DBPinnableBatch<'_>, Error>
1764 where
1765 K: AsRef<[u8]>,
1766 I: IntoIterator<Item = K>,
1767 {
1768 DEFAULT_READ_OPTS
1769 .with(|opts| self.batched_multi_get_pinned_batch_opt(keys, sorted_input, opts))
1770 }
1771
1772 pub fn batched_multi_get_pinned_batch_opt<K, I>(
1775 &'_ self,
1776 keys: I,
1777 sorted_input: bool,
1778 readopts: &ReadOptions,
1779 ) -> Result<DBPinnableBatch<'_>, Error>
1780 where
1781 K: AsRef<[u8]>,
1782 I: IntoIterator<Item = K>,
1783 {
1784 let owned_keys: Vec<K> = keys.into_iter().collect();
1785 let key_slices = Self::key_slices(&owned_keys);
1786 self.create_pinnable_batch(ptr::null_mut(), &key_slices, sorted_input, readopts)
1787 }
1788
1789 pub fn batched_multi_get_pinned_batch_cf<K, I>(
1791 &'_ self,
1792 cf: &impl AsColumnFamilyRef,
1793 keys: I,
1794 sorted_input: bool,
1795 ) -> Result<DBPinnableBatch<'_>, Error>
1796 where
1797 K: AsRef<[u8]>,
1798 I: IntoIterator<Item = K>,
1799 {
1800 DEFAULT_READ_OPTS
1801 .with(|opts| self.batched_multi_get_pinned_batch_cf_opt(cf, keys, sorted_input, opts))
1802 }
1803
1804 pub fn batched_multi_get_pinned_batch_cf_opt<K, I>(
1807 &'_ self,
1808 cf: &impl AsColumnFamilyRef,
1809 keys: I,
1810 sorted_input: bool,
1811 readopts: &ReadOptions,
1812 ) -> Result<DBPinnableBatch<'_>, Error>
1813 where
1814 K: AsRef<[u8]>,
1815 I: IntoIterator<Item = K>,
1816 {
1817 let owned_keys: Vec<K> = keys.into_iter().collect();
1818 let key_slices = Self::key_slices(&owned_keys);
1819 self.create_pinnable_batch(cf.inner(), &key_slices, sorted_input, readopts)
1820 }
1821
1822 pub fn multi_get_cf<'a, 'b: 'a, K, I, W>(
1824 &'a self,
1825 keys: I,
1826 ) -> Vec<Result<Option<Vec<u8>>, Error>>
1827 where
1828 K: AsRef<[u8]>,
1829 I: IntoIterator<Item = (&'b W, K)>,
1830 W: 'b + AsColumnFamilyRef,
1831 {
1832 DEFAULT_READ_OPTS.with(|opts| self.multi_get_cf_opt(keys, opts))
1833 }
1834
1835 pub fn multi_get_cf_opt<'a, 'b: 'a, K, I, W>(
1837 &'a self,
1838 keys: I,
1839 readopts: &ReadOptions,
1840 ) -> Vec<Result<Option<Vec<u8>>, Error>>
1841 where
1842 K: AsRef<[u8]>,
1843 I: IntoIterator<Item = (&'b W, K)>,
1844 W: 'b + AsColumnFamilyRef,
1845 {
1846 let cfs_and_owned_keys: Vec<(&'b W, K)> = keys.into_iter().collect();
1847 let (ptr_keys, keys_sizes): (Vec<*const c_char>, Vec<usize>) = cfs_and_owned_keys
1848 .iter()
1849 .map(|(_, k)| {
1850 let key = k.as_ref();
1851 (key.as_ptr() as *const c_char, key.len())
1852 })
1853 .unzip();
1854 let ptr_cfs: Vec<*const ffi::rocksdb_column_family_handle_t> = cfs_and_owned_keys
1855 .iter()
1856 .map(|(c, _)| c.inner().cast_const())
1857 .collect();
1858 let mut values: Vec<*mut c_char> = Vec::with_capacity(ptr_keys.len());
1859 let mut values_sizes: Vec<usize> = Vec::with_capacity(ptr_keys.len());
1860 let mut errors: Vec<*mut c_char> = Vec::with_capacity(ptr_keys.len());
1861 unsafe {
1862 ffi::rocksdb_multi_get_cf(
1863 self.inner.inner(),
1864 readopts.inner,
1865 ptr_cfs.as_ptr(),
1866 ptr_keys.len(),
1867 ptr_keys.as_ptr(),
1868 keys_sizes.as_ptr(),
1869 values.as_mut_ptr(),
1870 values_sizes.as_mut_ptr(),
1871 errors.as_mut_ptr(),
1872 );
1873 }
1874
1875 unsafe {
1876 values.set_len(ptr_keys.len());
1877 values_sizes.set_len(ptr_keys.len());
1878 errors.set_len(ptr_keys.len());
1879 }
1880
1881 convert_values(values, values_sizes, errors)
1882 }
1883
1884 pub fn batched_multi_get_cf<'a, K, I>(
1888 &'_ self,
1889 cf: &impl AsColumnFamilyRef,
1890 keys: I,
1891 sorted_input: bool,
1892 ) -> Vec<Result<Option<DBPinnableSlice<'_>>, Error>>
1893 where
1894 K: AsRef<[u8]> + 'a + ?Sized,
1895 I: IntoIterator<Item = &'a K>,
1896 {
1897 DEFAULT_READ_OPTS.with(|opts| self.batched_multi_get_cf_opt(cf, keys, sorted_input, opts))
1898 }
1899
1900 pub fn batched_multi_get_cf_opt<'a, K, I>(
1904 &'_ self,
1905 cf: &impl AsColumnFamilyRef,
1906 keys: I,
1907 sorted_input: bool,
1908 readopts: &ReadOptions,
1909 ) -> Vec<Result<Option<DBPinnableSlice<'_>>, Error>>
1910 where
1911 K: AsRef<[u8]> + 'a + ?Sized,
1912 I: IntoIterator<Item = &'a K>,
1913 {
1914 let key_slices: Vec<_> = keys
1915 .into_iter()
1916 .map(|k| {
1917 let k = k.as_ref();
1918 ffi::rocksdb_slice_t {
1919 data: k.as_ptr() as *const c_char,
1920 size: k.len(),
1921 }
1922 })
1923 .collect();
1924 self.batched_multi_get_pinned_inner(cf.inner(), &key_slices, sorted_input, readopts)
1925 }
1926
1927 pub fn batched_multi_get_cf_slice<'a, K, I>(
1984 &'_ self,
1985 cf: &impl AsColumnFamilyRef,
1986 keys: I,
1987 sorted_input: bool,
1988 ) -> Vec<Result<Option<DBPinnableSlice<'_>>, Error>>
1989 where
1990 K: AsRef<[u8]> + 'a + ?Sized,
1991 I: IntoIterator<Item = &'a K>,
1992 {
1993 DEFAULT_READ_OPTS
1994 .with(|opts| self.batched_multi_get_cf_slice_opt(cf, keys, sorted_input, opts))
1995 }
1996
1997 pub fn batched_multi_get_cf_slice_opt<'a, K, I>(
2005 &'_ self,
2006 cf: &impl AsColumnFamilyRef,
2007 keys: I,
2008 sorted_input: bool,
2009 readopts: &ReadOptions,
2010 ) -> Vec<Result<Option<DBPinnableSlice<'_>>, Error>>
2011 where
2012 K: AsRef<[u8]> + 'a + ?Sized,
2013 I: IntoIterator<Item = &'a K>,
2014 {
2015 let slices: Vec<ffi::rocksdb_slice_t> = keys
2017 .into_iter()
2018 .map(|k| {
2019 let k = k.as_ref();
2020 ffi::rocksdb_slice_t {
2021 data: k.as_ptr() as *const c_char,
2022 size: k.len(),
2023 }
2024 })
2025 .collect();
2026
2027 self.batched_multi_get_pinned_inner(cf.inner(), &slices, sorted_input, readopts)
2028 }
2029
2030 fn key_slices<K: AsRef<[u8]>>(keys: &[K]) -> Vec<ffi::rocksdb_slice_t> {
2031 keys.iter()
2032 .map(|key| {
2033 let key = key.as_ref();
2034 ffi::rocksdb_slice_t {
2035 data: key.as_ptr() as *const c_char,
2036 size: key.len(),
2037 }
2038 })
2039 .collect()
2040 }
2041
2042 fn batched_multi_get_pinned_owned<'a, K: AsRef<[u8]>>(
2043 &'a self,
2044 keys: &[K],
2045 sorted_input: bool,
2046 readopts: &ReadOptions,
2047 ) -> Vec<Result<Option<DBPinnableSlice<'a>>, Error>> {
2048 let key_slices = Self::key_slices(keys);
2049 if key_slices.is_empty() {
2050 return Vec::new();
2051 }
2052 let default_cf = OwnedColumnFamilyHandle::default_for(self.inner.inner());
2053 self.batched_multi_get_pinned_inner(default_cf.inner, &key_slices, sorted_input, readopts)
2054 }
2055
2056 fn create_pinnable_batch<'a>(
2057 &'a self,
2058 cf: *mut ffi::rocksdb_column_family_handle_t,
2059 keys: &[ffi::rocksdb_slice_t],
2060 sorted_input: bool,
2061 readopts: &ReadOptions,
2062 ) -> Result<DBPinnableBatch<'a>, Error> {
2063 let batch = unsafe {
2064 ffi_try!(ffi::rust_rocksdb_batched_multi_get_pinned(
2065 self.inner.inner(),
2066 readopts.inner,
2067 cf,
2068 keys.len(),
2069 keys.as_ptr(),
2070 c_uchar::from(sorted_input),
2071 ))
2072 };
2073 if batch.is_null() {
2074 return Err(Error::new(
2078 "rust_rocksdb_batched_multi_get_pinned returned no batch".to_owned(),
2079 ));
2080 }
2081 Ok(unsafe { DBPinnableBatch::from_c(batch) })
2083 }
2084
2085 fn batched_multi_get_pinned_inner<'a>(
2086 &'a self,
2087 cf: *mut ffi::rocksdb_column_family_handle_t,
2088 keys: &[ffi::rocksdb_slice_t],
2089 sorted_input: bool,
2090 readopts: &ReadOptions,
2091 ) -> Vec<Result<Option<DBPinnableSlice<'a>>, Error>> {
2092 if keys.is_empty() {
2093 return Vec::new();
2094 }
2095 let output = match self.execute_batched_multi_get(cf, keys, sorted_input, readopts) {
2096 Ok(output) => output,
2097 Err(error) => {
2098 let message = error.to_string();
2099 return (0..keys.len())
2100 .map(|_| Err(Error::new(message.clone())))
2101 .collect();
2102 }
2103 };
2104 output
2105 .values
2106 .into_iter()
2107 .zip(output.errors)
2108 .map(|(value, error)| unsafe { Self::convert_pinned_result(value, error) })
2109 .collect()
2110 }
2111
2112 fn execute_batched_multi_get(
2113 &self,
2114 cf: *mut ffi::rocksdb_column_family_handle_t,
2115 keys: &[ffi::rocksdb_slice_t],
2116 sorted_input: bool,
2117 readopts: &ReadOptions,
2118 ) -> Result<PinnedMultiGetOutput, Error> {
2119 let mut pinned_values = vec![ptr::null_mut(); keys.len()];
2120 let mut errors = vec![ptr::null_mut(); keys.len()];
2121 unsafe {
2122 ffi_try!(ffi::rust_rocksdb_batched_multi_get_cf_slice_safe(
2123 self.inner.inner(),
2124 readopts.inner,
2125 cf,
2126 keys.len(),
2127 keys.as_ptr(),
2128 pinned_values.as_mut_ptr(),
2129 errors.as_mut_ptr(),
2130 c_uchar::from(sorted_input),
2131 ));
2132 }
2133 Ok(PinnedMultiGetOutput {
2134 values: pinned_values,
2135 errors,
2136 })
2137 }
2138
2139 unsafe fn convert_pinned_result<'a>(
2146 value: *mut ffi::rocksdb_pinnableslice_t,
2147 error: *mut c_char,
2148 ) -> Result<Option<DBPinnableSlice<'a>>, Error> {
2149 if error.is_null() {
2150 return Ok((!value.is_null()).then(|| unsafe { DBPinnableSlice::from_c(value) }));
2151 }
2152 if !value.is_null() {
2153 unsafe {
2154 ffi::rocksdb_pinnableslice_destroy(value);
2155 }
2156 }
2157 Err(convert_rocksdb_error(error))
2158 }
2159
2160 pub fn key_may_exist<K: AsRef<[u8]>>(&self, key: K) -> bool {
2163 DEFAULT_READ_OPTS.with(|opts| self.key_may_exist_opt(key, opts))
2164 }
2165
2166 pub fn key_may_exist_opt<K: AsRef<[u8]>>(&self, key: K, readopts: &ReadOptions) -> bool {
2169 let key = key.as_ref();
2170 unsafe {
2171 0 != ffi::rocksdb_key_may_exist(
2172 self.inner.inner(),
2173 readopts.inner,
2174 key.as_ptr() as *const c_char,
2175 key.len() as size_t,
2176 ptr::null_mut(), ptr::null_mut(), ptr::null(), 0, ptr::null_mut(), )
2182 }
2183 }
2184
2185 pub fn key_may_exist_cf<K: AsRef<[u8]>>(&self, cf: &impl AsColumnFamilyRef, key: K) -> bool {
2188 DEFAULT_READ_OPTS.with(|opts| self.key_may_exist_cf_opt(cf, key, opts))
2189 }
2190
2191 pub fn key_may_exist_cf_opt<K: AsRef<[u8]>>(
2194 &self,
2195 cf: &impl AsColumnFamilyRef,
2196 key: K,
2197 readopts: &ReadOptions,
2198 ) -> bool {
2199 let key = key.as_ref();
2200 0 != unsafe {
2201 ffi::rocksdb_key_may_exist_cf(
2202 self.inner.inner(),
2203 readopts.inner,
2204 cf.inner(),
2205 key.as_ptr() as *const c_char,
2206 key.len() as size_t,
2207 ptr::null_mut(), ptr::null_mut(), ptr::null(), 0, ptr::null_mut(), )
2213 }
2214 }
2215
2216 pub fn key_may_exist_cf_opt_value<K: AsRef<[u8]>>(
2223 &self,
2224 cf: &impl AsColumnFamilyRef,
2225 key: K,
2226 readopts: &ReadOptions,
2227 ) -> (bool, Option<CSlice>) {
2228 let key = key.as_ref();
2229 let mut val: *mut c_char = ptr::null_mut();
2230 let mut val_len: usize = 0;
2231 let mut value_found: c_uchar = 0;
2232 let may_exists = 0
2233 != unsafe {
2234 ffi::rocksdb_key_may_exist_cf(
2235 self.inner.inner(),
2236 readopts.inner,
2237 cf.inner(),
2238 key.as_ptr() as *const c_char,
2239 key.len() as size_t,
2240 &raw mut val, &raw mut val_len, ptr::null(), 0, &raw mut value_found, )
2246 };
2247 if may_exists && value_found != 0 {
2250 (
2251 may_exists,
2252 Some(unsafe { CSlice::from_raw_parts(val, val_len) }),
2253 )
2254 } else {
2255 (may_exists, None)
2256 }
2257 }
2258
2259 fn create_inner_cf_handle(
2260 &self,
2261 name: impl CStrLike,
2262 opts: &Options,
2263 ) -> Result<*mut ffi::rocksdb_column_family_handle_t, Error> {
2264 let cf_name = name.bake().map_err(|err| {
2265 Error::new(format!(
2266 "Failed to convert path to CString when creating cf: {err}"
2267 ))
2268 })?;
2269
2270 let mut err: *mut ::libc::c_char = ::std::ptr::null_mut();
2273 let cf_handle = unsafe {
2274 ffi::rocksdb_create_column_family(
2275 self.inner.inner(),
2276 opts.inner,
2277 cf_name.as_ptr(),
2278 &raw mut err,
2279 )
2280 };
2281 if !err.is_null() {
2282 if !cf_handle.is_null() {
2283 unsafe { ffi::rocksdb_column_family_handle_destroy(cf_handle) };
2284 }
2285 return Err(convert_rocksdb_error(err));
2286 }
2287 Ok(cf_handle)
2288 }
2289
2290 pub fn iterator<'a: 'b, 'b>(
2291 &'a self,
2292 mode: IteratorMode,
2293 ) -> DBIteratorWithThreadMode<'b, Self> {
2294 let readopts = ReadOptions::default();
2295 self.iterator_opt(mode, readopts)
2296 }
2297
2298 pub fn iterator_opt<'a: 'b, 'b>(
2299 &'a self,
2300 mode: IteratorMode,
2301 readopts: ReadOptions,
2302 ) -> DBIteratorWithThreadMode<'b, Self> {
2303 DBIteratorWithThreadMode::new(self, readopts, mode)
2304 }
2305
2306 pub fn iterator_cf_opt<'a: 'b, 'b>(
2309 &'a self,
2310 cf_handle: &impl AsColumnFamilyRef,
2311 readopts: ReadOptions,
2312 mode: IteratorMode,
2313 ) -> DBIteratorWithThreadMode<'b, Self> {
2314 DBIteratorWithThreadMode::new_cf(self, cf_handle.inner(), readopts, mode)
2315 }
2316
2317 pub fn full_iterator<'a: 'b, 'b>(
2321 &'a self,
2322 mode: IteratorMode,
2323 ) -> DBIteratorWithThreadMode<'b, Self> {
2324 let mut opts = ReadOptions::default();
2325 opts.set_total_order_seek(true);
2326 DBIteratorWithThreadMode::new(self, opts, mode)
2327 }
2328
2329 pub fn prefix_iterator<'a: 'b, 'b, P: AsRef<[u8]>>(
2330 &'a self,
2331 prefix: P,
2332 ) -> DBIteratorWithThreadMode<'b, Self> {
2333 let mut opts = ReadOptions::default();
2334 opts.set_prefix_same_as_start(true);
2335 DBIteratorWithThreadMode::new(
2336 self,
2337 opts,
2338 IteratorMode::From(prefix.as_ref(), Direction::Forward),
2339 )
2340 }
2341
2342 pub fn iterator_cf<'a: 'b, 'b>(
2343 &'a self,
2344 cf_handle: &impl AsColumnFamilyRef,
2345 mode: IteratorMode,
2346 ) -> DBIteratorWithThreadMode<'b, Self> {
2347 let opts = ReadOptions::default();
2348 DBIteratorWithThreadMode::new_cf(self, cf_handle.inner(), opts, mode)
2349 }
2350
2351 pub fn full_iterator_cf<'a: 'b, 'b>(
2352 &'a self,
2353 cf_handle: &impl AsColumnFamilyRef,
2354 mode: IteratorMode,
2355 ) -> DBIteratorWithThreadMode<'b, Self> {
2356 let mut opts = ReadOptions::default();
2357 opts.set_total_order_seek(true);
2358 DBIteratorWithThreadMode::new_cf(self, cf_handle.inner(), opts, mode)
2359 }
2360
2361 pub fn prefix_iterator_cf<'a, P: AsRef<[u8]>>(
2362 &'a self,
2363 cf_handle: &impl AsColumnFamilyRef,
2364 prefix: P,
2365 ) -> DBIteratorWithThreadMode<'a, Self> {
2366 let mut opts = ReadOptions::default();
2367 opts.set_prefix_same_as_start(true);
2368 DBIteratorWithThreadMode::<'a, Self>::new_cf(
2369 self,
2370 cf_handle.inner(),
2371 opts,
2372 IteratorMode::From(prefix.as_ref(), Direction::Forward),
2373 )
2374 }
2375
2376 pub fn prefix_exists<P: AsRef<[u8]>>(&self, prefix: P) -> Result<bool, Error> {
2383 let p = prefix.as_ref();
2384 with_prefix_read_opts(p, |opts| self.prefix_exists_opt(p, opts))
2385 }
2386
2387 pub fn prefix_exists_opt<P: AsRef<[u8]>>(
2390 &self,
2391 prefix: P,
2392 readopts: &ReadOptions,
2393 ) -> Result<bool, Error> {
2394 let prefix = prefix.as_ref();
2395 let iter = unsafe { self.create_iterator(readopts) };
2396 let res = unsafe {
2397 ffi::rocksdb_iter_seek(
2398 iter,
2399 prefix.as_ptr() as *const c_char,
2400 prefix.len() as size_t,
2401 );
2402 if ffi::rocksdb_iter_valid(iter) != 0 {
2403 let mut key_len: size_t = 0;
2404 let key_ptr = ffi::rocksdb_iter_key(iter, &raw mut key_len);
2405 let key = if key_len == 0 {
2408 &[][..]
2409 } else {
2410 slice::from_raw_parts(key_ptr.cast::<u8>(), key_len as usize)
2411 };
2412 Ok(key.starts_with(prefix))
2413 } else if let Err(e) = (|| {
2414 ffi_try!(ffi::rocksdb_iter_get_error(iter));
2416 Ok::<(), Error>(())
2417 })() {
2418 Err(e)
2419 } else {
2420 Ok(false)
2421 }
2422 };
2423 unsafe { ffi::rocksdb_iter_destroy(iter) };
2424 res
2425 }
2426
2427 pub fn prefix_prober(&self) -> PrefixProber<'_, Self> {
2435 let mut opts = ReadOptions::default();
2436 opts.set_prefix_same_as_start(true);
2437 PrefixProber {
2438 raw: DBRawIteratorWithThreadMode::new(self, opts),
2439 }
2440 }
2441
2442 pub fn prefix_prober_with_opts(&self, readopts: ReadOptions) -> PrefixProber<'_, Self> {
2449 PrefixProber {
2450 raw: DBRawIteratorWithThreadMode::new(self, readopts),
2451 }
2452 }
2453
2454 pub fn prefix_prober_cf(&self, cf_handle: &impl AsColumnFamilyRef) -> PrefixProber<'_, Self> {
2457 let mut opts = ReadOptions::default();
2458 opts.set_prefix_same_as_start(true);
2459 PrefixProber {
2460 raw: DBRawIteratorWithThreadMode::new_cf(self, cf_handle.inner(), opts),
2461 }
2462 }
2463
2464 pub fn prefix_prober_cf_with_opts(
2469 &self,
2470 cf_handle: &impl AsColumnFamilyRef,
2471 readopts: ReadOptions,
2472 ) -> PrefixProber<'_, Self> {
2473 PrefixProber {
2474 raw: DBRawIteratorWithThreadMode::new_cf(self, cf_handle.inner(), readopts),
2475 }
2476 }
2477
2478 pub fn prefix_exists_cf<P: AsRef<[u8]>>(
2484 &self,
2485 cf_handle: &impl AsColumnFamilyRef,
2486 prefix: P,
2487 ) -> Result<bool, Error> {
2488 let p = prefix.as_ref();
2489 with_prefix_read_opts(p, |opts| self.prefix_exists_cf_opt(cf_handle, p, opts))
2490 }
2491
2492 pub fn prefix_exists_cf_opt<P: AsRef<[u8]>>(
2495 &self,
2496 cf_handle: &impl AsColumnFamilyRef,
2497 prefix: P,
2498 readopts: &ReadOptions,
2499 ) -> Result<bool, Error> {
2500 let prefix = prefix.as_ref();
2501 let iter = unsafe { self.create_iterator_cf(cf_handle.inner(), readopts) };
2502 let res = unsafe {
2503 ffi::rocksdb_iter_seek(
2504 iter,
2505 prefix.as_ptr() as *const c_char,
2506 prefix.len() as size_t,
2507 );
2508 if ffi::rocksdb_iter_valid(iter) != 0 {
2509 let mut key_len: size_t = 0;
2510 let key_ptr = ffi::rocksdb_iter_key(iter, &raw mut key_len);
2511 let key = if key_len == 0 {
2514 &[][..]
2515 } else {
2516 slice::from_raw_parts(key_ptr.cast::<u8>(), key_len as usize)
2517 };
2518 Ok(key.starts_with(prefix))
2519 } else if let Err(e) = (|| {
2520 ffi_try!(ffi::rocksdb_iter_get_error(iter));
2521 Ok::<(), Error>(())
2522 })() {
2523 Err(e)
2524 } else {
2525 Ok(false)
2526 }
2527 };
2528 unsafe { ffi::rocksdb_iter_destroy(iter) };
2529 res
2530 }
2531
2532 pub fn raw_iterator<'a: 'b, 'b>(&'a self) -> DBRawIteratorWithThreadMode<'b, Self> {
2534 let opts = ReadOptions::default();
2535 DBRawIteratorWithThreadMode::new(self, opts)
2536 }
2537
2538 pub fn raw_iterator_cf<'a: 'b, 'b>(
2540 &'a self,
2541 cf_handle: &impl AsColumnFamilyRef,
2542 ) -> DBRawIteratorWithThreadMode<'b, Self> {
2543 let opts = ReadOptions::default();
2544 DBRawIteratorWithThreadMode::new_cf(self, cf_handle.inner(), opts)
2545 }
2546
2547 pub fn raw_iterators_cf<'a, 'b, W, I>(
2555 &'a self,
2556 column_families: I,
2557 ) -> Result<Vec<DBRawIteratorWithThreadMode<'a, Self>>, Error>
2558 where
2559 W: AsColumnFamilyRef + 'b,
2560 I: IntoIterator<Item = &'b W>,
2561 {
2562 let mut cf_handles: Vec<_> = column_families
2563 .into_iter()
2564 .map(AsColumnFamilyRef::inner)
2565 .collect();
2566 if cf_handles.is_empty() {
2567 return Ok(Vec::new());
2568 }
2569 let created = self.create_iterators_cf(&mut cf_handles)?;
2570 Ok(created
2571 .handles
2572 .into_iter()
2573 .map(|handle| {
2574 DBRawIteratorWithThreadMode::from_inner(handle, Arc::clone(&created.readopts))
2575 })
2576 .collect())
2577 }
2578
2579 fn create_iterators_cf(
2580 &self,
2581 cf_handles: &mut [*mut ffi::rocksdb_column_family_handle_t],
2582 ) -> Result<CreatedIterators, Error> {
2583 let mut iterator_handles = vec![ptr::null_mut(); cf_handles.len()];
2584 let readopts = Arc::new(ReadOptions::default());
2590 unsafe {
2591 ffi_try!(ffi::rust_rocksdb_create_iterators_safe(
2592 self.inner.inner(),
2593 readopts.inner,
2594 cf_handles.as_mut_ptr(),
2595 iterator_handles.as_mut_ptr(),
2596 iterator_handles.len(),
2597 ));
2598 }
2599 Self::validate_created_iterators(&iterator_handles)?;
2600 Ok(CreatedIterators {
2601 readopts,
2602 handles: iterator_handles,
2603 })
2604 }
2605
2606 fn validate_created_iterators(
2607 iterator_handles: &[*mut ffi::rocksdb_iterator_t],
2608 ) -> Result<(), Error> {
2609 if iterator_handles.iter().any(|iterator| iterator.is_null()) {
2610 unsafe {
2611 Self::destroy_iterators(iterator_handles);
2612 }
2613 return Err(Error::new(
2614 "rocksdb_create_iterators returned a null iterator".to_owned(),
2615 ));
2616 }
2617 Ok(())
2618 }
2619
2620 unsafe fn destroy_iterators(iterators: &[*mut ffi::rocksdb_iterator_t]) {
2626 for &iterator in iterators {
2627 if !iterator.is_null() {
2628 unsafe {
2629 ffi::rocksdb_iter_destroy(iterator);
2630 }
2631 }
2632 }
2633 }
2634
2635 pub fn raw_iterator_opt<'a: 'b, 'b>(
2637 &'a self,
2638 readopts: ReadOptions,
2639 ) -> DBRawIteratorWithThreadMode<'b, Self> {
2640 DBRawIteratorWithThreadMode::new(self, readopts)
2641 }
2642
2643 pub fn raw_iterator_cf_opt<'a: 'b, 'b>(
2645 &'a self,
2646 cf_handle: &impl AsColumnFamilyRef,
2647 readopts: ReadOptions,
2648 ) -> DBRawIteratorWithThreadMode<'b, Self> {
2649 DBRawIteratorWithThreadMode::new_cf(self, cf_handle.inner(), readopts)
2650 }
2651
2652 pub fn snapshot(&'_ self) -> SnapshotWithThreadMode<'_, Self> {
2653 SnapshotWithThreadMode::<Self>::new(self)
2654 }
2655
2656 pub fn put_opt<K, V>(&self, key: K, value: V, writeopts: &WriteOptions) -> Result<(), Error>
2657 where
2658 K: AsRef<[u8]>,
2659 V: AsRef<[u8]>,
2660 {
2661 let key = key.as_ref();
2662 let value = value.as_ref();
2663
2664 unsafe {
2665 ffi_try!(ffi::rocksdb_put(
2666 self.inner.inner(),
2667 writeopts.inner,
2668 key.as_ptr() as *const c_char,
2669 key.len() as size_t,
2670 value.as_ptr() as *const c_char,
2671 value.len() as size_t,
2672 ));
2673 Ok(())
2674 }
2675 }
2676
2677 pub fn put_cf_opt<K, V>(
2678 &self,
2679 cf: &impl AsColumnFamilyRef,
2680 key: K,
2681 value: V,
2682 writeopts: &WriteOptions,
2683 ) -> Result<(), Error>
2684 where
2685 K: AsRef<[u8]>,
2686 V: AsRef<[u8]>,
2687 {
2688 let key = key.as_ref();
2689 let value = value.as_ref();
2690
2691 unsafe {
2692 ffi_try!(ffi::rocksdb_put_cf(
2693 self.inner.inner(),
2694 writeopts.inner,
2695 cf.inner(),
2696 key.as_ptr() as *const c_char,
2697 key.len() as size_t,
2698 value.as_ptr() as *const c_char,
2699 value.len() as size_t,
2700 ));
2701 Ok(())
2702 }
2703 }
2704
2705 pub fn put_with_ts_opt<K, V, S>(
2712 &self,
2713 key: K,
2714 ts: S,
2715 value: V,
2716 writeopts: &WriteOptions,
2717 ) -> Result<(), Error>
2718 where
2719 K: AsRef<[u8]>,
2720 V: AsRef<[u8]>,
2721 S: AsRef<[u8]>,
2722 {
2723 let key = key.as_ref();
2724 let value = value.as_ref();
2725 let ts = ts.as_ref();
2726 unsafe {
2727 ffi_try!(ffi::rocksdb_put_with_ts(
2728 self.inner.inner(),
2729 writeopts.inner,
2730 key.as_ptr() as *const c_char,
2731 key.len() as size_t,
2732 ts.as_ptr() as *const c_char,
2733 ts.len() as size_t,
2734 value.as_ptr() as *const c_char,
2735 value.len() as size_t,
2736 ));
2737 Ok(())
2738 }
2739 }
2740
2741 pub fn put_cf_with_ts_opt<K, V, S>(
2748 &self,
2749 cf: &impl AsColumnFamilyRef,
2750 key: K,
2751 ts: S,
2752 value: V,
2753 writeopts: &WriteOptions,
2754 ) -> Result<(), Error>
2755 where
2756 K: AsRef<[u8]>,
2757 V: AsRef<[u8]>,
2758 S: AsRef<[u8]>,
2759 {
2760 let key = key.as_ref();
2761 let value = value.as_ref();
2762 let ts = ts.as_ref();
2763 unsafe {
2764 ffi_try!(ffi::rocksdb_put_cf_with_ts(
2765 self.inner.inner(),
2766 writeopts.inner,
2767 cf.inner(),
2768 key.as_ptr() as *const c_char,
2769 key.len() as size_t,
2770 ts.as_ptr() as *const c_char,
2771 ts.len() as size_t,
2772 value.as_ptr() as *const c_char,
2773 value.len() as size_t,
2774 ));
2775 Ok(())
2776 }
2777 }
2778
2779 pub fn merge_opt<K, V>(&self, key: K, value: V, writeopts: &WriteOptions) -> Result<(), Error>
2780 where
2781 K: AsRef<[u8]>,
2782 V: AsRef<[u8]>,
2783 {
2784 let key = key.as_ref();
2785 let value = value.as_ref();
2786
2787 unsafe {
2788 ffi_try!(ffi::rocksdb_merge(
2789 self.inner.inner(),
2790 writeopts.inner,
2791 key.as_ptr() as *const c_char,
2792 key.len() as size_t,
2793 value.as_ptr() as *const c_char,
2794 value.len() as size_t,
2795 ));
2796 Ok(())
2797 }
2798 }
2799
2800 pub fn merge_cf_opt<K, V>(
2801 &self,
2802 cf: &impl AsColumnFamilyRef,
2803 key: K,
2804 value: V,
2805 writeopts: &WriteOptions,
2806 ) -> Result<(), Error>
2807 where
2808 K: AsRef<[u8]>,
2809 V: AsRef<[u8]>,
2810 {
2811 let key = key.as_ref();
2812 let value = value.as_ref();
2813
2814 unsafe {
2815 ffi_try!(ffi::rocksdb_merge_cf(
2816 self.inner.inner(),
2817 writeopts.inner,
2818 cf.inner(),
2819 key.as_ptr() as *const c_char,
2820 key.len() as size_t,
2821 value.as_ptr() as *const c_char,
2822 value.len() as size_t,
2823 ));
2824 Ok(())
2825 }
2826 }
2827
2828 pub fn delete_opt<K: AsRef<[u8]>>(
2829 &self,
2830 key: K,
2831 writeopts: &WriteOptions,
2832 ) -> Result<(), Error> {
2833 let key = key.as_ref();
2834
2835 unsafe {
2836 ffi_try!(ffi::rocksdb_delete(
2837 self.inner.inner(),
2838 writeopts.inner,
2839 key.as_ptr() as *const c_char,
2840 key.len() as size_t,
2841 ));
2842 Ok(())
2843 }
2844 }
2845
2846 pub fn delete_cf_opt<K: AsRef<[u8]>>(
2847 &self,
2848 cf: &impl AsColumnFamilyRef,
2849 key: K,
2850 writeopts: &WriteOptions,
2851 ) -> Result<(), Error> {
2852 let key = key.as_ref();
2853
2854 unsafe {
2855 ffi_try!(ffi::rocksdb_delete_cf(
2856 self.inner.inner(),
2857 writeopts.inner,
2858 cf.inner(),
2859 key.as_ptr() as *const c_char,
2860 key.len() as size_t,
2861 ));
2862 Ok(())
2863 }
2864 }
2865
2866 pub fn delete_with_ts_opt<K, S>(
2870 &self,
2871 key: K,
2872 ts: S,
2873 writeopts: &WriteOptions,
2874 ) -> Result<(), Error>
2875 where
2876 K: AsRef<[u8]>,
2877 S: AsRef<[u8]>,
2878 {
2879 let key = key.as_ref();
2880 let ts = ts.as_ref();
2881 unsafe {
2882 ffi_try!(ffi::rocksdb_delete_with_ts(
2883 self.inner.inner(),
2884 writeopts.inner,
2885 key.as_ptr() as *const c_char,
2886 key.len() as size_t,
2887 ts.as_ptr() as *const c_char,
2888 ts.len() as size_t,
2889 ));
2890 Ok(())
2891 }
2892 }
2893
2894 pub fn delete_cf_with_ts_opt<K, S>(
2898 &self,
2899 cf: &impl AsColumnFamilyRef,
2900 key: K,
2901 ts: S,
2902 writeopts: &WriteOptions,
2903 ) -> Result<(), Error>
2904 where
2905 K: AsRef<[u8]>,
2906 S: AsRef<[u8]>,
2907 {
2908 let key = key.as_ref();
2909 let ts = ts.as_ref();
2910 unsafe {
2911 ffi_try!(ffi::rocksdb_delete_cf_with_ts(
2912 self.inner.inner(),
2913 writeopts.inner,
2914 cf.inner(),
2915 key.as_ptr() as *const c_char,
2916 key.len() as size_t,
2917 ts.as_ptr() as *const c_char,
2918 ts.len() as size_t,
2919 ));
2920 Ok(())
2921 }
2922 }
2923
2924 pub fn put<K, V>(&self, key: K, value: V) -> Result<(), Error>
2925 where
2926 K: AsRef<[u8]>,
2927 V: AsRef<[u8]>,
2928 {
2929 DEFAULT_WRITE_OPTS.with(|opts| self.put_opt(key, value, opts))
2930 }
2931
2932 pub fn put_cf<K, V>(&self, cf: &impl AsColumnFamilyRef, key: K, value: V) -> Result<(), Error>
2933 where
2934 K: AsRef<[u8]>,
2935 V: AsRef<[u8]>,
2936 {
2937 DEFAULT_WRITE_OPTS.with(|opts| self.put_cf_opt(cf, key, value, opts))
2938 }
2939
2940 pub fn put_with_ts<K, V, S>(&self, key: K, ts: S, value: V) -> Result<(), Error>
2947 where
2948 K: AsRef<[u8]>,
2949 V: AsRef<[u8]>,
2950 S: AsRef<[u8]>,
2951 {
2952 DEFAULT_WRITE_OPTS
2953 .with(|opts| self.put_with_ts_opt(key.as_ref(), ts.as_ref(), value.as_ref(), opts))
2954 }
2955
2956 pub fn put_cf_with_ts<K, V, S>(
2963 &self,
2964 cf: &impl AsColumnFamilyRef,
2965 key: K,
2966 ts: S,
2967 value: V,
2968 ) -> Result<(), Error>
2969 where
2970 K: AsRef<[u8]>,
2971 V: AsRef<[u8]>,
2972 S: AsRef<[u8]>,
2973 {
2974 DEFAULT_WRITE_OPTS.with(|opts| {
2975 self.put_cf_with_ts_opt(cf, key.as_ref(), ts.as_ref(), value.as_ref(), opts)
2976 })
2977 }
2978
2979 pub fn merge<K, V>(&self, key: K, value: V) -> Result<(), Error>
2980 where
2981 K: AsRef<[u8]>,
2982 V: AsRef<[u8]>,
2983 {
2984 DEFAULT_WRITE_OPTS.with(|opts| self.merge_opt(key, value, opts))
2985 }
2986
2987 pub fn merge_cf<K, V>(&self, cf: &impl AsColumnFamilyRef, key: K, value: V) -> Result<(), Error>
2988 where
2989 K: AsRef<[u8]>,
2990 V: AsRef<[u8]>,
2991 {
2992 DEFAULT_WRITE_OPTS.with(|opts| self.merge_cf_opt(cf, key, value, opts))
2993 }
2994
2995 pub fn delete<K: AsRef<[u8]>>(&self, key: K) -> Result<(), Error> {
2996 DEFAULT_WRITE_OPTS.with(|opts| self.delete_opt(key, opts))
2997 }
2998
2999 pub fn delete_cf<K: AsRef<[u8]>>(
3000 &self,
3001 cf: &impl AsColumnFamilyRef,
3002 key: K,
3003 ) -> Result<(), Error> {
3004 DEFAULT_WRITE_OPTS.with(|opts| self.delete_cf_opt(cf, key, opts))
3005 }
3006
3007 pub fn delete_with_ts<K: AsRef<[u8]>, S: AsRef<[u8]>>(
3011 &self,
3012 key: K,
3013 ts: S,
3014 ) -> Result<(), Error> {
3015 DEFAULT_WRITE_OPTS.with(|opts| self.delete_with_ts_opt(key, ts, opts))
3016 }
3017
3018 pub fn delete_cf_with_ts<K: AsRef<[u8]>, S: AsRef<[u8]>>(
3022 &self,
3023 cf: &impl AsColumnFamilyRef,
3024 key: K,
3025 ts: S,
3026 ) -> Result<(), Error> {
3027 DEFAULT_WRITE_OPTS.with(|opts| self.delete_cf_with_ts_opt(cf, key, ts, opts))
3028 }
3029
3030 pub fn single_delete_opt<K: AsRef<[u8]>>(
3050 &self,
3051 key: K,
3052 writeopts: &WriteOptions,
3053 ) -> Result<(), Error> {
3054 let key = key.as_ref();
3055
3056 unsafe {
3057 ffi_try!(ffi::rocksdb_singledelete(
3058 self.inner.inner(),
3059 writeopts.inner,
3060 key.as_ptr() as *const c_char,
3061 key.len() as size_t,
3062 ));
3063 Ok(())
3064 }
3065 }
3066
3067 pub fn single_delete_cf_opt<K: AsRef<[u8]>>(
3071 &self,
3072 cf: &impl AsColumnFamilyRef,
3073 key: K,
3074 writeopts: &WriteOptions,
3075 ) -> Result<(), Error> {
3076 let key = key.as_ref();
3077
3078 unsafe {
3079 ffi_try!(ffi::rocksdb_singledelete_cf(
3080 self.inner.inner(),
3081 writeopts.inner,
3082 cf.inner(),
3083 key.as_ptr() as *const c_char,
3084 key.len() as size_t,
3085 ));
3086 Ok(())
3087 }
3088 }
3089
3090 pub fn single_delete_with_ts_opt<K, S>(
3097 &self,
3098 key: K,
3099 ts: S,
3100 writeopts: &WriteOptions,
3101 ) -> Result<(), Error>
3102 where
3103 K: AsRef<[u8]>,
3104 S: AsRef<[u8]>,
3105 {
3106 let key = key.as_ref();
3107 let ts = ts.as_ref();
3108 unsafe {
3109 ffi_try!(ffi::rocksdb_singledelete_with_ts(
3110 self.inner.inner(),
3111 writeopts.inner,
3112 key.as_ptr() as *const c_char,
3113 key.len() as size_t,
3114 ts.as_ptr() as *const c_char,
3115 ts.len() as size_t,
3116 ));
3117 Ok(())
3118 }
3119 }
3120
3121 pub fn single_delete_cf_with_ts_opt<K, S>(
3128 &self,
3129 cf: &impl AsColumnFamilyRef,
3130 key: K,
3131 ts: S,
3132 writeopts: &WriteOptions,
3133 ) -> Result<(), Error>
3134 where
3135 K: AsRef<[u8]>,
3136 S: AsRef<[u8]>,
3137 {
3138 let key = key.as_ref();
3139 let ts = ts.as_ref();
3140 unsafe {
3141 ffi_try!(ffi::rocksdb_singledelete_cf_with_ts(
3142 self.inner.inner(),
3143 writeopts.inner,
3144 cf.inner(),
3145 key.as_ptr() as *const c_char,
3146 key.len() as size_t,
3147 ts.as_ptr() as *const c_char,
3148 ts.len() as size_t,
3149 ));
3150 Ok(())
3151 }
3152 }
3153
3154 pub fn single_delete<K: AsRef<[u8]>>(&self, key: K) -> Result<(), Error> {
3158 DEFAULT_WRITE_OPTS.with(|opts| self.single_delete_opt(key, opts))
3159 }
3160
3161 pub fn single_delete_cf<K: AsRef<[u8]>>(
3165 &self,
3166 cf: &impl AsColumnFamilyRef,
3167 key: K,
3168 ) -> Result<(), Error> {
3169 DEFAULT_WRITE_OPTS.with(|opts| self.single_delete_cf_opt(cf, key, opts))
3170 }
3171
3172 pub fn single_delete_with_ts<K: AsRef<[u8]>, S: AsRef<[u8]>>(
3179 &self,
3180 key: K,
3181 ts: S,
3182 ) -> Result<(), Error> {
3183 DEFAULT_WRITE_OPTS.with(|opts| self.single_delete_with_ts_opt(key, ts, opts))
3184 }
3185
3186 pub fn single_delete_cf_with_ts<K: AsRef<[u8]>, S: AsRef<[u8]>>(
3193 &self,
3194 cf: &impl AsColumnFamilyRef,
3195 key: K,
3196 ts: S,
3197 ) -> Result<(), Error> {
3198 DEFAULT_WRITE_OPTS.with(|opts| self.single_delete_cf_with_ts_opt(cf, key, ts, opts))
3199 }
3200
3201 pub fn compact_range<S: AsRef<[u8]>, E: AsRef<[u8]>>(&self, start: Option<S>, end: Option<E>) {
3203 unsafe {
3204 let start = start.as_ref().map(AsRef::as_ref);
3205 let end = end.as_ref().map(AsRef::as_ref);
3206
3207 ffi::rocksdb_compact_range(
3208 self.inner.inner(),
3209 opt_bytes_to_ptr(start),
3210 start.map_or(0, <[u8]>::len) as size_t,
3211 opt_bytes_to_ptr(end),
3212 end.map_or(0, <[u8]>::len) as size_t,
3213 );
3214 }
3215 }
3216
3217 pub fn compact_range_opt<S: AsRef<[u8]>, E: AsRef<[u8]>>(
3219 &self,
3220 start: Option<S>,
3221 end: Option<E>,
3222 opts: &CompactOptions,
3223 ) {
3224 unsafe {
3225 let start = start.as_ref().map(AsRef::as_ref);
3226 let end = end.as_ref().map(AsRef::as_ref);
3227
3228 ffi::rocksdb_compact_range_opt(
3229 self.inner.inner(),
3230 opts.inner,
3231 opt_bytes_to_ptr(start),
3232 start.map_or(0, <[u8]>::len) as size_t,
3233 opt_bytes_to_ptr(end),
3234 end.map_or(0, <[u8]>::len) as size_t,
3235 );
3236 }
3237 }
3238
3239 pub fn compact_range_cf<S: AsRef<[u8]>, E: AsRef<[u8]>>(
3242 &self,
3243 cf: &impl AsColumnFamilyRef,
3244 start: Option<S>,
3245 end: Option<E>,
3246 ) {
3247 unsafe {
3248 let start = start.as_ref().map(AsRef::as_ref);
3249 let end = end.as_ref().map(AsRef::as_ref);
3250
3251 ffi::rocksdb_compact_range_cf(
3252 self.inner.inner(),
3253 cf.inner(),
3254 opt_bytes_to_ptr(start),
3255 start.map_or(0, <[u8]>::len) as size_t,
3256 opt_bytes_to_ptr(end),
3257 end.map_or(0, <[u8]>::len) as size_t,
3258 );
3259 }
3260 }
3261
3262 pub fn compact_range_cf_opt<S: AsRef<[u8]>, E: AsRef<[u8]>>(
3264 &self,
3265 cf: &impl AsColumnFamilyRef,
3266 start: Option<S>,
3267 end: Option<E>,
3268 opts: &CompactOptions,
3269 ) {
3270 unsafe {
3271 let start = start.as_ref().map(AsRef::as_ref);
3272 let end = end.as_ref().map(AsRef::as_ref);
3273
3274 ffi::rocksdb_compact_range_cf_opt(
3275 self.inner.inner(),
3276 cf.inner(),
3277 opts.inner,
3278 opt_bytes_to_ptr(start),
3279 start.map_or(0, <[u8]>::len) as size_t,
3280 opt_bytes_to_ptr(end),
3281 end.map_or(0, <[u8]>::len) as size_t,
3282 );
3283 }
3284 }
3285
3286 pub fn wait_for_compact(&self, opts: &WaitForCompactOptions) -> Result<(), Error> {
3295 unsafe {
3296 ffi_try!(ffi::rocksdb_wait_for_compact(
3297 self.inner.inner(),
3298 opts.inner
3299 ));
3300 }
3301 Ok(())
3302 }
3303
3304 pub fn set_options(&self, opts: &[(&str, &str)]) -> Result<(), Error> {
3305 let copts = convert_options(opts)?;
3306 let cnames: Vec<*const c_char> = copts.iter().map(|opt| opt.0.as_ptr()).collect();
3307 let cvalues: Vec<*const c_char> = copts.iter().map(|opt| opt.1.as_ptr()).collect();
3308 let count = opts.len() as i32;
3309 unsafe {
3310 ffi_try!(ffi::rocksdb_set_options(
3311 self.inner.inner(),
3312 count,
3313 cnames.as_ptr(),
3314 cvalues.as_ptr(),
3315 ));
3316 }
3317 Ok(())
3318 }
3319
3320 pub fn set_options_cf(
3321 &self,
3322 cf: &impl AsColumnFamilyRef,
3323 opts: &[(&str, &str)],
3324 ) -> Result<(), Error> {
3325 let copts = convert_options(opts)?;
3326 let cnames: Vec<*const c_char> = copts.iter().map(|opt| opt.0.as_ptr()).collect();
3327 let cvalues: Vec<*const c_char> = copts.iter().map(|opt| opt.1.as_ptr()).collect();
3328 let count = opts.len() as i32;
3329 unsafe {
3330 ffi_try!(ffi::rocksdb_set_options_cf(
3331 self.inner.inner(),
3332 cf.inner(),
3333 count,
3334 cnames.as_ptr(),
3335 cvalues.as_ptr(),
3336 ));
3337 }
3338 Ok(())
3339 }
3340
3341 fn property_value_impl<R>(
3350 name: impl CStrLike,
3351 get_property: impl FnOnce(*const c_char) -> *mut c_char,
3352 parse: impl FnOnce(&str) -> Result<R, Error>,
3353 ) -> Result<Option<R>, Error> {
3354 let value = match name.bake() {
3355 Ok(prop_name) => get_property(prop_name.as_ptr()),
3356 Err(e) => {
3357 return Err(Error::new(format!(
3358 "Failed to convert property name to CString: {e}"
3359 )));
3360 }
3361 };
3362 if value.is_null() {
3363 return Ok(None);
3364 }
3365 let result = match unsafe { CStr::from_ptr(value) }.to_str() {
3366 Ok(s) => parse(s).map(|value| Some(value)),
3367 Err(e) => Err(Error::new(format!(
3368 "Failed to convert property value to string: {e}"
3369 ))),
3370 };
3371 unsafe {
3372 ffi::rocksdb_free(value as *mut c_void);
3373 }
3374 result
3375 }
3376
3377 pub fn property_value(&self, name: impl CStrLike) -> Result<Option<String>, Error> {
3382 Self::property_value_impl(
3383 name,
3384 |prop_name| unsafe { ffi::rocksdb_property_value(self.inner.inner(), prop_name) },
3385 |str_value| Ok(str_value.to_owned()),
3386 )
3387 }
3388
3389 pub fn property_value_cf(
3394 &self,
3395 cf: &impl AsColumnFamilyRef,
3396 name: impl CStrLike,
3397 ) -> Result<Option<String>, Error> {
3398 Self::property_value_impl(
3399 name,
3400 |prop_name| unsafe {
3401 ffi::rocksdb_property_value_cf(self.inner.inner(), cf.inner(), prop_name)
3402 },
3403 |str_value| Ok(str_value.to_owned()),
3404 )
3405 }
3406
3407 fn property_int_value_impl(
3408 name: impl CStrLike,
3409 get_property: impl FnOnce(*const c_char, *mut u64) -> c_int,
3410 get_string_property: impl FnOnce(*const c_char) -> *mut c_char,
3411 ) -> Result<Option<u64>, Error> {
3412 let prop_name = name.bake().map_err(|err| {
3413 Error::new(format!("Failed to convert property name to CString: {err}"))
3414 })?;
3415 let mut value = 0;
3416 if get_property(prop_name.as_ptr(), &raw mut value) == 0 {
3417 return Ok(Some(value));
3418 }
3419
3420 Self::property_value_impl(
3421 prop_name.as_ref(),
3422 get_string_property,
3423 Self::parse_property_int_value,
3424 )
3425 }
3426
3427 fn parse_property_int_value(value: &str) -> Result<u64, Error> {
3428 value.parse::<u64>().map_err(|err| {
3429 Error::new(format!(
3430 "Failed to convert property value {value} to int: {err}"
3431 ))
3432 })
3433 }
3434
3435 pub fn property_int_value(&self, name: impl CStrLike) -> Result<Option<u64>, Error> {
3440 Self::property_int_value_impl(
3441 name,
3442 |prop_name, value| unsafe {
3443 ffi::rocksdb_property_int(self.inner.inner(), prop_name, value)
3444 },
3445 |prop_name| unsafe { ffi::rocksdb_property_value(self.inner.inner(), prop_name) },
3446 )
3447 }
3448
3449 pub fn property_int_value_cf(
3454 &self,
3455 cf: &impl AsColumnFamilyRef,
3456 name: impl CStrLike,
3457 ) -> Result<Option<u64>, Error> {
3458 Self::property_int_value_impl(
3459 name,
3460 |prop_name, value| unsafe {
3461 ffi::rocksdb_property_int_cf(self.inner.inner(), cf.inner(), prop_name, value)
3462 },
3463 |prop_name| unsafe {
3464 ffi::rocksdb_property_value_cf(self.inner.inner(), cf.inner(), prop_name)
3465 },
3466 )
3467 }
3468
3469 pub fn latest_sequence_number(&self) -> u64 {
3471 unsafe { ffi::rocksdb_get_latest_sequence_number(self.inner.inner()) }
3472 }
3473
3474 pub fn get_approximate_sizes(&self, ranges: &[Range]) -> Result<Vec<u64>, Error> {
3487 self.get_approximate_sizes_cfopt(None::<&ColumnFamily>, ranges)
3488 }
3489
3490 pub fn get_approximate_sizes_cf(
3496 &self,
3497 cf: &impl AsColumnFamilyRef,
3498 ranges: &[Range],
3499 ) -> Result<Vec<u64>, Error> {
3500 self.get_approximate_sizes_cfopt(Some(cf), ranges)
3501 }
3502
3503 fn get_approximate_sizes_cfopt(
3504 &self,
3505 cf: Option<&impl AsColumnFamilyRef>,
3506 ranges: &[Range],
3507 ) -> Result<Vec<u64>, Error> {
3508 let start_keys: Vec<*const c_char> = ranges
3509 .iter()
3510 .map(|x| x.start_key.as_ptr() as *const c_char)
3511 .collect();
3512 let start_key_lens: Vec<_> = ranges.iter().map(|x| x.start_key.len()).collect();
3513 let end_keys: Vec<*const c_char> = ranges
3514 .iter()
3515 .map(|x| x.end_key.as_ptr() as *const c_char)
3516 .collect();
3517 let end_key_lens: Vec<_> = ranges.iter().map(|x| x.end_key.len()).collect();
3518 let mut sizes: Vec<u64> = vec![0; ranges.len()];
3519 let (n, start_key_ptr, start_key_len_ptr, end_key_ptr, end_key_len_ptr, size_ptr) = (
3520 ranges.len() as i32,
3521 start_keys.as_ptr(),
3522 start_key_lens.as_ptr(),
3523 end_keys.as_ptr(),
3524 end_key_lens.as_ptr(),
3525 sizes.as_mut_ptr(),
3526 );
3527 let mut err: *mut c_char = ptr::null_mut();
3528 match cf {
3529 None => unsafe {
3530 ffi::rocksdb_approximate_sizes(
3531 self.inner.inner(),
3532 n,
3533 start_key_ptr,
3534 start_key_len_ptr,
3535 end_key_ptr,
3536 end_key_len_ptr,
3537 size_ptr,
3538 &raw mut err,
3539 );
3540 },
3541 Some(cf) => unsafe {
3542 ffi::rocksdb_approximate_sizes_cf(
3543 self.inner.inner(),
3544 cf.inner(),
3545 n,
3546 start_key_ptr,
3547 start_key_len_ptr,
3548 end_key_ptr,
3549 end_key_len_ptr,
3550 size_ptr,
3551 &raw mut err,
3552 );
3553 },
3554 }
3555 if !err.is_null() {
3559 return Err(convert_rocksdb_error(err));
3560 }
3561 Ok(sizes)
3562 }
3563
3564 pub fn get_updates_since(&self, seq_number: u64) -> Result<DBWALIterator, Error> {
3575 unsafe {
3576 let opts: *const ffi::rocksdb_wal_readoptions_t = ptr::null();
3580 let iter = ffi_try!(ffi::rocksdb_get_updates_since(
3581 self.inner.inner(),
3582 seq_number,
3583 opts
3584 ));
3585 Ok(DBWALIterator {
3586 inner: iter,
3587 start_seq_number: seq_number,
3588 })
3589 }
3590 }
3591
3592 pub fn try_catch_up_with_primary(&self) -> Result<(), Error> {
3595 unsafe {
3596 ffi_try!(ffi::rocksdb_try_catch_up_with_primary(self.inner.inner()));
3597 }
3598 Ok(())
3599 }
3600
3601 pub fn ingest_external_file<P: AsRef<Path>>(&self, paths: Vec<P>) -> Result<(), Error> {
3603 let opts = IngestExternalFileOptions::default();
3604 self.ingest_external_file_opts(&opts, paths)
3605 }
3606
3607 pub fn ingest_external_file_opts<P: AsRef<Path>>(
3609 &self,
3610 opts: &IngestExternalFileOptions,
3611 paths: Vec<P>,
3612 ) -> Result<(), Error> {
3613 let paths_v: Vec<CString> = paths.iter().map(to_cpath).collect::<Result<Vec<_>, _>>()?;
3614 let cpaths: Vec<_> = paths_v.iter().map(|path| path.as_ptr()).collect();
3615
3616 self.ingest_external_file_raw(opts, &paths_v, &cpaths)
3617 }
3618
3619 pub fn ingest_external_file_cf<P: AsRef<Path>>(
3622 &self,
3623 cf: &impl AsColumnFamilyRef,
3624 paths: Vec<P>,
3625 ) -> Result<(), Error> {
3626 let opts = IngestExternalFileOptions::default();
3627 self.ingest_external_file_cf_opts(cf, &opts, paths)
3628 }
3629
3630 pub fn ingest_external_file_cf_opts<P: AsRef<Path>>(
3632 &self,
3633 cf: &impl AsColumnFamilyRef,
3634 opts: &IngestExternalFileOptions,
3635 paths: Vec<P>,
3636 ) -> Result<(), Error> {
3637 let paths_v: Vec<CString> = paths.iter().map(to_cpath).collect::<Result<Vec<_>, _>>()?;
3638 let cpaths: Vec<_> = paths_v.iter().map(|path| path.as_ptr()).collect();
3639
3640 self.ingest_external_file_raw_cf(cf, opts, &paths_v, &cpaths)
3641 }
3642
3643 fn ingest_external_file_raw(
3644 &self,
3645 opts: &IngestExternalFileOptions,
3646 paths_v: &[CString],
3647 cpaths: &[*const c_char],
3648 ) -> Result<(), Error> {
3649 unsafe {
3650 ffi_try!(ffi::rocksdb_ingest_external_file(
3651 self.inner.inner(),
3652 cpaths.as_ptr(),
3653 paths_v.len(),
3654 opts.inner.cast_const()
3655 ));
3656 Ok(())
3657 }
3658 }
3659
3660 fn ingest_external_file_raw_cf(
3661 &self,
3662 cf: &impl AsColumnFamilyRef,
3663 opts: &IngestExternalFileOptions,
3664 paths_v: &[CString],
3665 cpaths: &[*const c_char],
3666 ) -> Result<(), Error> {
3667 unsafe {
3668 ffi_try!(ffi::rocksdb_ingest_external_file_cf(
3669 self.inner.inner(),
3670 cf.inner(),
3671 cpaths.as_ptr(),
3672 paths_v.len(),
3673 opts.inner.cast_const()
3674 ));
3675 Ok(())
3676 }
3677 }
3678
3679 pub fn get_column_family_metadata(&self) -> ColumnFamilyMetaData {
3681 unsafe {
3682 let ptr = ffi::rocksdb_get_column_family_metadata(self.inner.inner());
3683
3684 let metadata = ColumnFamilyMetaData {
3685 size: ffi::rocksdb_column_family_metadata_get_size(ptr),
3686 name: from_cstr_and_free(ffi::rocksdb_column_family_metadata_get_name(ptr)),
3687 file_count: ffi::rocksdb_column_family_metadata_get_file_count(ptr),
3688 };
3689
3690 ffi::rocksdb_column_family_metadata_destroy(ptr);
3692
3693 metadata
3695 }
3696 }
3697
3698 pub fn get_column_family_metadata_cf(
3700 &self,
3701 cf: &impl AsColumnFamilyRef,
3702 ) -> ColumnFamilyMetaData {
3703 unsafe {
3704 let ptr = ffi::rocksdb_get_column_family_metadata_cf(self.inner.inner(), cf.inner());
3705
3706 let metadata = ColumnFamilyMetaData {
3707 size: ffi::rocksdb_column_family_metadata_get_size(ptr),
3708 name: from_cstr_and_free(ffi::rocksdb_column_family_metadata_get_name(ptr)),
3709 file_count: ffi::rocksdb_column_family_metadata_get_file_count(ptr),
3710 };
3711
3712 ffi::rocksdb_column_family_metadata_destroy(ptr);
3714
3715 metadata
3717 }
3718 }
3719
3720 pub fn live_files(&self) -> Result<Vec<LiveFile>, Error> {
3723 unsafe {
3724 let livefiles_ptr = ffi::rocksdb_livefiles(self.inner.inner());
3725 if livefiles_ptr.is_null() {
3726 Err(Error::new("Could not get live files".to_owned()))
3727 } else {
3728 let files = LiveFile::from_rocksdb_livefiles_ptr(livefiles_ptr);
3729
3730 ffi::rocksdb_livefiles_destroy(livefiles_ptr);
3732
3733 Ok(files)
3735 }
3736 }
3737 }
3738
3739 pub fn delete_file_in_range<K: AsRef<[u8]>>(&self, from: K, to: K) -> Result<(), Error> {
3748 let from = from.as_ref();
3749 let to = to.as_ref();
3750 unsafe {
3751 ffi_try!(ffi::rocksdb_delete_file_in_range(
3752 self.inner.inner(),
3753 from.as_ptr() as *const c_char,
3754 from.len() as size_t,
3755 to.as_ptr() as *const c_char,
3756 to.len() as size_t,
3757 ));
3758 Ok(())
3759 }
3760 }
3761
3762 pub fn delete_file_in_range_cf<K: AsRef<[u8]>>(
3764 &self,
3765 cf: &impl AsColumnFamilyRef,
3766 from: K,
3767 to: K,
3768 ) -> Result<(), Error> {
3769 let from = from.as_ref();
3770 let to = to.as_ref();
3771 unsafe {
3772 ffi_try!(ffi::rocksdb_delete_file_in_range_cf(
3773 self.inner.inner(),
3774 cf.inner(),
3775 from.as_ptr() as *const c_char,
3776 from.len() as size_t,
3777 to.as_ptr() as *const c_char,
3778 to.len() as size_t,
3779 ));
3780 Ok(())
3781 }
3782 }
3783
3784 pub fn cancel_all_background_work(&self, wait: bool) {
3786 unsafe {
3787 ffi::rocksdb_cancel_all_background_work(self.inner.inner(), c_uchar::from(wait));
3788 }
3789 }
3790
3791 fn mark_column_family_dropped(
3805 &self,
3806 cf_inner: *mut ffi::rocksdb_column_family_handle_t,
3807 ) -> Result<(), Error> {
3808 unsafe {
3809 ffi_try!(ffi::rocksdb_drop_column_family(
3810 self.inner.inner(),
3811 cf_inner
3812 ));
3813 }
3814 Ok(())
3815 }
3816
3817 pub fn increase_full_history_ts_low<S: AsRef<[u8]>>(
3822 &self,
3823 cf: &impl AsColumnFamilyRef,
3824 ts: S,
3825 ) -> Result<(), Error> {
3826 let ts = ts.as_ref();
3827 unsafe {
3828 ffi_try!(ffi::rocksdb_increase_full_history_ts_low(
3829 self.inner.inner(),
3830 cf.inner(),
3831 ts.as_ptr() as *const c_char,
3832 ts.len() as size_t,
3833 ));
3834 Ok(())
3835 }
3836 }
3837
3838 pub fn get_full_history_ts_low(&self, cf: &impl AsColumnFamilyRef) -> Result<Vec<u8>, Error> {
3840 unsafe {
3841 let mut ts_lowlen = 0;
3842 let ts = ffi_try!(ffi::rocksdb_get_full_history_ts_low(
3843 self.inner.inner(),
3844 cf.inner(),
3845 &raw mut ts_lowlen,
3846 ));
3847
3848 if ts.is_null() {
3849 Err(Error::new("Could not get full_history_ts_low".to_owned()))
3850 } else {
3851 let mut vec = vec![0; ts_lowlen];
3852 ptr::copy_nonoverlapping(ts.cast::<u8>(), vec.as_mut_ptr(), ts_lowlen);
3853 ffi::rocksdb_free(ts as *mut c_void);
3854 Ok(vec)
3855 }
3856 }
3857 }
3858
3859 pub fn get_db_identity(&self) -> Result<Vec<u8>, Error> {
3861 unsafe {
3862 let mut length: usize = 0;
3863 let identity_ptr = ffi::rocksdb_get_db_identity(self.inner.inner(), &raw mut length);
3864 let identity_vec = raw_data(identity_ptr, length);
3865 ffi::rocksdb_free(identity_ptr as *mut c_void);
3866 identity_vec.ok_or_else(|| Error::new("get_db_identity returned NULL".to_string()))
3869 }
3870 }
3871}
3872
3873impl<I: DBInner> DBCommon<SingleThreaded, I> {
3874 pub fn create_cf<N: AsRef<str>>(&mut self, name: N, opts: &Options) -> Result<(), Error> {
3876 let inner = self.create_inner_cf_handle(name.as_ref(), opts)?;
3877 self.cfs
3878 .cfs
3879 .insert(name.as_ref().to_string(), ColumnFamily { inner });
3880 Ok(())
3881 }
3882
3883 #[doc = include_str!("db_create_column_family_with_import.md")]
3884 pub fn create_column_family_with_import<N: AsRef<str>>(
3885 &mut self,
3886 options: &Options,
3887 column_family_name: N,
3888 import_options: &ImportColumnFamilyOptions,
3889 metadata: &ExportImportFilesMetaData,
3890 ) -> Result<(), Error> {
3891 let name = column_family_name.as_ref();
3892 let c_name = CString::new(name).map_err(|err| {
3893 Error::new(format!(
3894 "Failed to convert name to CString while importing column family: {err}"
3895 ))
3896 })?;
3897 let inner = unsafe {
3898 ffi_try!(ffi::rocksdb_create_column_family_with_import(
3899 self.inner.inner(),
3900 options.inner,
3901 c_name.as_ptr(),
3902 import_options.inner,
3903 metadata.inner
3904 ))
3905 };
3906 self.cfs
3907 .cfs
3908 .insert(column_family_name.as_ref().into(), ColumnFamily { inner });
3909 Ok(())
3910 }
3911
3912 pub fn drop_cf(&mut self, name: &str) -> Result<(), Error> {
3914 let Some(cf) = self.cfs.cfs.remove(name) else {
3915 return Err(Error::new(format!("Invalid column family: {name}")));
3916 };
3917 match self.mark_column_family_dropped(cf.inner) {
3918 Ok(()) => Ok(()),
3923 Err(e) => {
3924 self.cfs.cfs.insert(name.to_owned(), cf);
3927 Err(e)
3928 }
3929 }
3930 }
3931
3932 pub fn cf_handle(&self, name: &str) -> Option<&ColumnFamily> {
3934 self.cfs.cfs.get(name)
3935 }
3936
3937 pub fn cf_names(&self) -> Vec<String> {
3941 self.cfs.cfs.keys().cloned().collect()
3942 }
3943}
3944
3945impl<I: DBInner> DBCommon<MultiThreaded, I> {
3946 pub fn create_cf<N: AsRef<str>>(&self, name: N, opts: &Options) -> Result<(), Error> {
3948 let mut cfs = self.cfs.cfs.write();
3951 let inner = self.create_inner_cf_handle(name.as_ref(), opts)?;
3952 cfs.insert(
3953 name.as_ref().to_string(),
3954 Arc::new(UnboundColumnFamily { inner }),
3955 );
3956 Ok(())
3957 }
3958
3959 #[doc = include_str!("db_create_column_family_with_import.md")]
3960 pub fn create_column_family_with_import<N: AsRef<str>>(
3961 &self,
3962 options: &Options,
3963 column_family_name: N,
3964 import_options: &ImportColumnFamilyOptions,
3965 metadata: &ExportImportFilesMetaData,
3966 ) -> Result<(), Error> {
3967 let mut cfs = self.cfs.cfs.write();
3969 let name = column_family_name.as_ref();
3970 let c_name = CString::new(name).map_err(|err| {
3971 Error::new(format!(
3972 "Failed to convert name to CString while importing column family: {err}"
3973 ))
3974 })?;
3975 let inner = unsafe {
3976 ffi_try!(ffi::rocksdb_create_column_family_with_import(
3977 self.inner.inner(),
3978 options.inner,
3979 c_name.as_ptr(),
3980 import_options.inner,
3981 metadata.inner
3982 ))
3983 };
3984 cfs.insert(
3985 column_family_name.as_ref().to_string(),
3986 Arc::new(UnboundColumnFamily { inner }),
3987 );
3988 Ok(())
3989 }
3990
3991 pub fn drop_cf(&self, name: &str) -> Result<(), Error> {
3994 let Some(cf) = self.cfs.cfs.write().remove(name) else {
4000 return Err(Error::new(format!("Invalid column family: {name}")));
4001 };
4002 match self.mark_column_family_dropped(cf.inner) {
4003 Ok(()) => Ok(()),
4008 Err(e) => {
4009 self.cfs.cfs.write().insert(name.to_owned(), cf);
4012 Err(e)
4013 }
4014 }
4015 }
4016
4017 pub fn cf_handle(&'_ self, name: &str) -> Option<Arc<BoundColumnFamily<'_>>> {
4019 self.cfs
4020 .cfs
4021 .read()
4022 .get(name)
4023 .cloned()
4024 .map(UnboundColumnFamily::bound_column_family)
4025 }
4026
4027 pub fn cf_names(&self) -> Vec<String> {
4031 self.cfs.cfs.read().keys().cloned().collect()
4032 }
4033}
4034
4035impl<T: ThreadMode, I: DBInner> Drop for DBCommon<T, I> {
4036 fn drop(&mut self) {
4037 self.cfs.drop_all_cfs_internal();
4038 }
4039}
4040
4041impl<T: ThreadMode, I: DBInner> fmt::Debug for DBCommon<T, I> {
4042 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4043 write!(f, "RocksDB {{ path: {} }}", self.path().display())
4044 }
4045}
4046
4047#[derive(Debug, Clone)]
4049pub struct ColumnFamilyMetaData {
4050 pub size: u64,
4053 pub name: String,
4055 pub file_count: usize,
4057}
4058
4059#[derive(Debug, Clone)]
4061pub struct LiveFile {
4062 pub column_family_name: String,
4064 pub name: String,
4066 pub directory: String,
4069 pub size: usize,
4071 pub level: i32,
4073 pub start_key: Option<Vec<u8>>,
4075 pub end_key: Option<Vec<u8>>,
4077 pub smallest_seqno: u64,
4078 pub largest_seqno: u64,
4079 pub num_entries: u64,
4081 pub num_deletions: u64,
4083}
4084
4085impl LiveFile {
4086 pub(crate) fn from_rocksdb_livefiles_ptr(
4088 files: *const ffi::rocksdb_livefiles_t,
4089 ) -> Vec<LiveFile> {
4090 unsafe {
4091 let n = ffi::rocksdb_livefiles_count(files);
4092
4093 let mut livefiles = Vec::with_capacity(n as usize);
4094 let mut key_size: usize = 0;
4095
4096 for i in 0..n {
4097 let column_family_name =
4099 from_cstr_without_free(ffi::rocksdb_livefiles_column_family_name(files, i));
4100 let name = from_cstr_without_free(ffi::rocksdb_livefiles_name(files, i));
4101 let directory = from_cstr_without_free(ffi::rocksdb_livefiles_directory(files, i));
4102 let size = ffi::rocksdb_livefiles_size(files, i);
4103 let level = ffi::rocksdb_livefiles_level(files, i);
4104
4105 let smallest_key = ffi::rocksdb_livefiles_smallestkey(files, i, &raw mut key_size);
4107 let smallest_key = raw_data(smallest_key, key_size);
4108
4109 let largest_key = ffi::rocksdb_livefiles_largestkey(files, i, &raw mut key_size);
4111 let largest_key = raw_data(largest_key, key_size);
4112
4113 livefiles.push(LiveFile {
4114 column_family_name,
4115 name,
4116 directory,
4117 size,
4118 level,
4119 start_key: smallest_key,
4120 end_key: largest_key,
4121 largest_seqno: ffi::rocksdb_livefiles_largest_seqno(files, i),
4122 smallest_seqno: ffi::rocksdb_livefiles_smallest_seqno(files, i),
4123 num_entries: ffi::rocksdb_livefiles_entries(files, i),
4124 num_deletions: ffi::rocksdb_livefiles_deletions(files, i),
4125 });
4126 }
4127
4128 livefiles
4129 }
4130 }
4131}
4132
4133struct LiveFileGuard(*mut rocksdb_livefile_t);
4134
4135impl LiveFileGuard {
4136 fn into_raw(mut self) -> *mut rocksdb_livefile_t {
4137 let ptr = self.0;
4138 self.0 = ptr::null_mut();
4139 ptr
4140 }
4141}
4142
4143impl Drop for LiveFileGuard {
4144 fn drop(&mut self) {
4145 if !self.0.is_null() {
4146 unsafe {
4147 rocksdb_livefile_destroy(self.0);
4148 }
4149 }
4150 }
4151}
4152
4153struct LiveFilesGuard(*mut rocksdb_livefiles_t);
4154
4155impl LiveFilesGuard {
4156 fn into_raw(mut self) -> *mut rocksdb_livefiles_t {
4157 let ptr = self.0;
4158 self.0 = ptr::null_mut();
4159 ptr
4160 }
4161}
4162
4163impl Drop for LiveFilesGuard {
4164 fn drop(&mut self) {
4165 if !self.0.is_null() {
4166 unsafe {
4167 rocksdb_livefiles_destroy(self.0);
4168 }
4169 }
4170 }
4171}
4172
4173#[derive(Debug)]
4178pub struct ExportImportFilesMetaData {
4179 pub(crate) inner: *mut ffi::rocksdb_export_import_files_metadata_t,
4180}
4181
4182impl ExportImportFilesMetaData {
4183 pub fn get_db_comparator_name(&self) -> String {
4184 unsafe {
4185 let c_name =
4186 ffi::rocksdb_export_import_files_metadata_get_db_comparator_name(self.inner);
4187 from_cstr_and_free(c_name)
4188 }
4189 }
4190
4191 pub fn set_db_comparator_name(&mut self, name: &str) {
4192 let c_name = CString::new(name.as_bytes()).unwrap();
4193 unsafe {
4194 ffi::rocksdb_export_import_files_metadata_set_db_comparator_name(
4195 self.inner,
4196 c_name.as_ptr(),
4197 );
4198 };
4199 }
4200
4201 pub fn get_files(&self) -> Vec<LiveFile> {
4202 unsafe {
4203 let livefiles_ptr = ffi::rocksdb_export_import_files_metadata_get_files(self.inner);
4204 let files = LiveFile::from_rocksdb_livefiles_ptr(livefiles_ptr);
4205 ffi::rocksdb_livefiles_destroy(livefiles_ptr);
4206 files
4207 }
4208 }
4209
4210 pub fn set_files(&mut self, files: &[LiveFile]) -> Result<(), Error> {
4211 static EMPTY: [u8; 0] = [];
4213 let empty_ptr = EMPTY.as_ptr() as *const libc::c_char;
4214
4215 unsafe {
4216 let live_files = LiveFilesGuard(ffi::rocksdb_livefiles_create());
4217
4218 for file in files {
4219 let live_file = LiveFileGuard(ffi::rocksdb_livefile_create());
4220 ffi::rocksdb_livefile_set_level(live_file.0, file.level);
4221
4222 let c_cf_name = CString::new(file.column_family_name.as_str()).map_err(|err| {
4224 Error::new(format!("Unable to convert column family to CString: {err}"))
4225 })?;
4226 ffi::rocksdb_livefile_set_column_family_name(live_file.0, c_cf_name.as_ptr());
4227
4228 let c_name = CString::new(file.name.as_str()).map_err(|err| {
4229 Error::new(format!("Unable to convert file name to CString: {err}"))
4230 })?;
4231 ffi::rocksdb_livefile_set_name(live_file.0, c_name.as_ptr());
4232
4233 let c_directory = CString::new(file.directory.as_str()).map_err(|err| {
4234 Error::new(format!("Unable to convert directory to CString: {err}"))
4235 })?;
4236 ffi::rocksdb_livefile_set_directory(live_file.0, c_directory.as_ptr());
4237
4238 ffi::rocksdb_livefile_set_size(live_file.0, file.size);
4239
4240 let (start_key_ptr, start_key_len) = match &file.start_key {
4241 None => (empty_ptr, 0),
4242 Some(key) => (key.as_ptr() as *const libc::c_char, key.len()),
4243 };
4244 ffi::rocksdb_livefile_set_smallest_key(live_file.0, start_key_ptr, start_key_len);
4245
4246 let (largest_key_ptr, largest_key_len) = match &file.end_key {
4247 None => (empty_ptr, 0),
4248 Some(key) => (key.as_ptr() as *const libc::c_char, key.len()),
4249 };
4250 ffi::rocksdb_livefile_set_largest_key(
4251 live_file.0,
4252 largest_key_ptr,
4253 largest_key_len,
4254 );
4255 ffi::rocksdb_livefile_set_smallest_seqno(live_file.0, file.smallest_seqno);
4256 ffi::rocksdb_livefile_set_largest_seqno(live_file.0, file.largest_seqno);
4257 ffi::rocksdb_livefile_set_num_entries(live_file.0, file.num_entries);
4258 ffi::rocksdb_livefile_set_num_deletions(live_file.0, file.num_deletions);
4259
4260 ffi::rocksdb_livefiles_add(live_files.0, live_file.into_raw());
4262 }
4263
4264 ffi::rocksdb_export_import_files_metadata_set_files(self.inner, live_files.into_raw());
4266 Ok(())
4267 }
4268 }
4269}
4270
4271impl Default for ExportImportFilesMetaData {
4272 fn default() -> Self {
4273 let inner = unsafe { ffi::rocksdb_export_import_files_metadata_create() };
4274 assert!(
4275 !inner.is_null(),
4276 "Could not create rocksdb_export_import_files_metadata_t"
4277 );
4278
4279 Self { inner }
4280 }
4281}
4282
4283impl Drop for ExportImportFilesMetaData {
4284 fn drop(&mut self) {
4285 unsafe {
4286 ffi::rocksdb_export_import_files_metadata_destroy(self.inner);
4287 }
4288 }
4289}
4290
4291unsafe impl Send for ExportImportFilesMetaData {}
4292unsafe impl Sync for ExportImportFilesMetaData {}
4293
4294fn ttl_to_seconds(ttl: Duration) -> c_int {
4308 c_int::try_from(ttl.as_secs()).unwrap_or(c_int::MAX)
4309}
4310
4311fn convert_options(opts: &[(&str, &str)]) -> Result<Vec<(CString, CString)>, Error> {
4312 opts.iter()
4313 .map(|(name, value)| {
4314 let cname = match CString::new(name.as_bytes()) {
4315 Ok(cname) => cname,
4316 Err(e) => return Err(Error::new(format!("Invalid option name `{e}`"))),
4317 };
4318 let cvalue = match CString::new(value.as_bytes()) {
4319 Ok(cvalue) => cvalue,
4320 Err(e) => return Err(Error::new(format!("Invalid option value: `{e}`"))),
4321 };
4322 Ok((cname, cvalue))
4323 })
4324 .collect()
4325}
4326
4327pub(crate) fn convert_values(
4328 values: Vec<*mut c_char>,
4329 values_sizes: Vec<usize>,
4330 errors: Vec<*mut c_char>,
4331) -> Vec<Result<Option<Vec<u8>>, Error>> {
4332 values
4333 .into_iter()
4334 .zip(values_sizes)
4335 .zip(errors)
4336 .map(|((v, s), e)| {
4337 if e.is_null() {
4338 let value = unsafe { crate::ffi_util::raw_data(v, s) };
4339 unsafe {
4340 ffi::rocksdb_free(v as *mut c_void);
4341 }
4342 Ok(value)
4343 } else {
4344 Err(convert_rocksdb_error(e))
4345 }
4346 })
4347 .collect()
4348}
4349
4350#[cfg(test)]
4351mod tests {
4352 use crate::{ColumnFamilyDescriptor, DB, Options};
4353
4354 #[test]
4361 fn raw_iterators_cf_share_one_live_readopts() {
4362 let dir = tempfile::Builder::new()
4363 .prefix("rocksdb-raw-iterators-cf-readopts")
4364 .tempdir()
4365 .unwrap();
4366
4367 let mut opts = Options::default();
4368 opts.create_if_missing(true);
4369 opts.create_missing_column_families(true);
4370 let db = DB::open_cf_descriptors(
4371 &opts,
4372 dir.path(),
4373 [
4374 ColumnFamilyDescriptor::new("first", Options::default()),
4375 ColumnFamilyDescriptor::new("second", Options::default()),
4376 ],
4377 )
4378 .unwrap();
4379
4380 let first = db.cf_handle("first").unwrap();
4381 let second = db.cf_handle("second").unwrap();
4382 let iterators = db.raw_iterators_cf([&first, &second]).unwrap();
4383 assert_eq!(iterators.len(), 2);
4384
4385 let shared = iterators[0].readopts_ptr();
4386 assert!(!shared.is_null());
4387 for iterator in &iterators {
4388 assert_eq!(
4389 iterator.readopts_ptr(),
4390 shared,
4391 "each iterator must hold the options object it was created from"
4392 );
4393 }
4394 }
4395}