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 DBPinnableSlice, DBRawIteratorWithThreadMode, DBWALIterator, DEFAULT_COLUMN_FAMILY_NAME,
35 Direction, Error, FlushOptions, IngestExternalFileOptions, IteratorMode, Options, ReadOptions,
36 SnapshotWithThreadMode, WaitForCompactOptions, WriteBatch, WriteBatchWithIndex, WriteOptions,
37 column_family::{AsColumnFamilyRef, BoundColumnFamily, UnboundColumnFamily},
38 db_options::{ImportColumnFamilyOptions, OptionsMustOutliveDB},
39 ffi,
40 ffi_util::{
41 CStrLike, convert_rocksdb_error, from_cstr_and_free, from_cstr_without_free,
42 opt_bytes_to_ptr, raw_data, to_cpath,
43 },
44};
45use rust_librocksdb_sys::{
46 rocksdb_livefile_destroy, rocksdb_livefile_t, rocksdb_livefiles_destroy, rocksdb_livefiles_t,
47};
48
49use libc::{self, c_char, c_int, c_uchar, c_void, size_t};
50use parking_lot::RwLock;
51
52thread_local! { static DEFAULT_READ_OPTS: ReadOptions = ReadOptions::default(); }
59thread_local! { static DEFAULT_WRITE_OPTS: WriteOptions = WriteOptions::default(); }
60thread_local! { static DEFAULT_FLUSH_OPTS: FlushOptions = FlushOptions::default(); }
61thread_local! { static PREFIX_READ_OPTS: RefCell<ReadOptions> = RefCell::new({ let mut o = ReadOptions::default(); o.set_prefix_same_as_start(true); o }); }
63
64pub struct Range<'a> {
68 start_key: &'a [u8],
69 end_key: &'a [u8],
70}
71
72impl<'a> Range<'a> {
73 pub fn new(start_key: &'a [u8], end_key: &'a [u8]) -> Range<'a> {
74 Range { start_key, end_key }
75 }
76}
77
78#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
117pub enum GetIntoBufferResult {
118 NotFound,
120 Found(usize),
123 BufferTooSmall(usize),
129}
130
131impl GetIntoBufferResult {
132 #[inline]
134 pub fn is_found(&self) -> bool {
135 matches!(self, Self::Found(_) | Self::BufferTooSmall(_))
136 }
137
138 #[inline]
140 pub fn is_not_found(&self) -> bool {
141 matches!(self, Self::NotFound)
142 }
143
144 #[inline]
146 pub fn value_size(&self) -> Option<usize> {
147 match self {
148 Self::Found(size) | Self::BufferTooSmall(size) => Some(*size),
149 Self::NotFound => None,
150 }
151 }
152}
153
154pub struct PrefixProber<'a, D: DBAccess> {
158 raw: DBRawIteratorWithThreadMode<'a, D>,
159}
160
161impl<D: DBAccess> PrefixProber<'_, D> {
162 pub fn exists(&mut self, prefix: &[u8]) -> Result<bool, Error> {
165 self.raw.seek(prefix);
166 if self.raw.valid()
167 && let Some(k) = self.raw.key()
168 {
169 return Ok(k.starts_with(prefix));
170 }
171 self.raw.status()?;
172 Ok(false)
173 }
174}
175
176pub trait ThreadMode {
187 fn new_cf_map_internal(
189 cf_map: BTreeMap<String, *mut ffi::rocksdb_column_family_handle_t>,
190 ) -> Self;
191 fn drop_all_cfs_internal(&mut self);
193}
194
195pub struct SingleThreaded {
202 pub(crate) cfs: HashMap<String, ColumnFamily>,
203}
204
205pub struct MultiThreaded {
211 pub(crate) cfs: RwLock<HashMap<String, Arc<UnboundColumnFamily>>>,
212}
213
214impl ThreadMode for SingleThreaded {
215 fn new_cf_map_internal(
216 cfs: BTreeMap<String, *mut ffi::rocksdb_column_family_handle_t>,
217 ) -> Self {
218 Self {
219 cfs: cfs
220 .into_iter()
221 .map(|(n, c)| (n, ColumnFamily { inner: c }))
222 .collect(),
223 }
224 }
225
226 fn drop_all_cfs_internal(&mut self) {
227 self.cfs.clear();
229 }
230}
231
232impl ThreadMode for MultiThreaded {
233 fn new_cf_map_internal(
234 cfs: BTreeMap<String, *mut ffi::rocksdb_column_family_handle_t>,
235 ) -> Self {
236 Self {
237 cfs: RwLock::new(
238 cfs.into_iter()
239 .map(|(n, c)| (n, Arc::new(UnboundColumnFamily { inner: c })))
240 .collect(),
241 ),
242 }
243 }
244
245 fn drop_all_cfs_internal(&mut self) {
246 self.cfs.write().clear();
248 }
249}
250
251pub trait DBInner {
253 fn inner(&self) -> *mut ffi::rocksdb_t;
254}
255
256pub struct DBCommon<T: ThreadMode, D: DBInner> {
277 pub(crate) inner: D,
278 cfs: T, path: PathBuf,
280 _outlive: Vec<OptionsMustOutliveDB>,
281}
282
283pub trait DBAccess {
286 unsafe fn create_snapshot(&self) -> *const ffi::rocksdb_snapshot_t;
287
288 unsafe fn release_snapshot(&self, snapshot: *const ffi::rocksdb_snapshot_t);
289
290 unsafe fn create_iterator(&self, readopts: &ReadOptions) -> *mut ffi::rocksdb_iterator_t;
291
292 unsafe fn create_iterator_cf(
293 &self,
294 cf_handle: *mut ffi::rocksdb_column_family_handle_t,
295 readopts: &ReadOptions,
296 ) -> *mut ffi::rocksdb_iterator_t;
297
298 fn get_opt<K: AsRef<[u8]>>(
299 &self,
300 key: K,
301 readopts: &ReadOptions,
302 ) -> Result<Option<Vec<u8>>, Error>;
303
304 fn get_cf_opt<K: AsRef<[u8]>>(
305 &self,
306 cf: &impl AsColumnFamilyRef,
307 key: K,
308 readopts: &ReadOptions,
309 ) -> Result<Option<Vec<u8>>, Error>;
310
311 fn get_pinned_opt<K: AsRef<[u8]>>(
312 &'_ self,
313 key: K,
314 readopts: &ReadOptions,
315 ) -> Result<Option<DBPinnableSlice<'_>>, Error>;
316
317 fn get_pinned_cf_opt<K: AsRef<[u8]>>(
318 &'_ self,
319 cf: &impl AsColumnFamilyRef,
320 key: K,
321 readopts: &ReadOptions,
322 ) -> Result<Option<DBPinnableSlice<'_>>, Error>;
323
324 fn multi_get_opt<K, I>(
325 &self,
326 keys: I,
327 readopts: &ReadOptions,
328 ) -> Vec<Result<Option<Vec<u8>>, Error>>
329 where
330 K: AsRef<[u8]>,
331 I: IntoIterator<Item = K>;
332
333 fn multi_get_cf_opt<'b, K, I, W>(
334 &self,
335 keys_cf: I,
336 readopts: &ReadOptions,
337 ) -> Vec<Result<Option<Vec<u8>>, Error>>
338 where
339 K: AsRef<[u8]>,
340 I: IntoIterator<Item = (&'b W, K)>,
341 W: AsColumnFamilyRef + 'b;
342}
343
344impl<T: ThreadMode, D: DBInner> DBAccess for DBCommon<T, D> {
345 unsafe fn create_snapshot(&self) -> *const ffi::rocksdb_snapshot_t {
346 unsafe { ffi::rocksdb_create_snapshot(self.inner.inner()) }
347 }
348
349 unsafe fn release_snapshot(&self, snapshot: *const ffi::rocksdb_snapshot_t) {
350 unsafe {
351 ffi::rocksdb_release_snapshot(self.inner.inner(), snapshot);
352 }
353 }
354
355 unsafe fn create_iterator(&self, readopts: &ReadOptions) -> *mut ffi::rocksdb_iterator_t {
356 unsafe { ffi::rocksdb_create_iterator(self.inner.inner(), readopts.inner) }
357 }
358
359 unsafe fn create_iterator_cf(
360 &self,
361 cf_handle: *mut ffi::rocksdb_column_family_handle_t,
362 readopts: &ReadOptions,
363 ) -> *mut ffi::rocksdb_iterator_t {
364 unsafe { ffi::rocksdb_create_iterator_cf(self.inner.inner(), readopts.inner, cf_handle) }
365 }
366
367 fn get_opt<K: AsRef<[u8]>>(
368 &self,
369 key: K,
370 readopts: &ReadOptions,
371 ) -> Result<Option<Vec<u8>>, Error> {
372 self.get_opt(key, readopts)
373 }
374
375 fn get_cf_opt<K: AsRef<[u8]>>(
376 &self,
377 cf: &impl AsColumnFamilyRef,
378 key: K,
379 readopts: &ReadOptions,
380 ) -> Result<Option<Vec<u8>>, Error> {
381 self.get_cf_opt(cf, key, readopts)
382 }
383
384 fn get_pinned_opt<K: AsRef<[u8]>>(
385 &'_ self,
386 key: K,
387 readopts: &ReadOptions,
388 ) -> Result<Option<DBPinnableSlice<'_>>, Error> {
389 self.get_pinned_opt(key, readopts)
390 }
391
392 fn get_pinned_cf_opt<K: AsRef<[u8]>>(
393 &'_ self,
394 cf: &impl AsColumnFamilyRef,
395 key: K,
396 readopts: &ReadOptions,
397 ) -> Result<Option<DBPinnableSlice<'_>>, Error> {
398 self.get_pinned_cf_opt(cf, key, readopts)
399 }
400
401 fn multi_get_opt<K, Iter>(
402 &self,
403 keys: Iter,
404 readopts: &ReadOptions,
405 ) -> Vec<Result<Option<Vec<u8>>, Error>>
406 where
407 K: AsRef<[u8]>,
408 Iter: IntoIterator<Item = K>,
409 {
410 self.multi_get_opt(keys, readopts)
411 }
412
413 fn multi_get_cf_opt<'b, K, Iter, W>(
414 &self,
415 keys_cf: Iter,
416 readopts: &ReadOptions,
417 ) -> Vec<Result<Option<Vec<u8>>, Error>>
418 where
419 K: AsRef<[u8]>,
420 Iter: IntoIterator<Item = (&'b W, K)>,
421 W: AsColumnFamilyRef + 'b,
422 {
423 self.multi_get_cf_opt(keys_cf, readopts)
424 }
425}
426
427pub struct DBWithThreadModeInner {
428 inner: *mut ffi::rocksdb_t,
429}
430
431impl DBInner for DBWithThreadModeInner {
432 fn inner(&self) -> *mut ffi::rocksdb_t {
433 self.inner
434 }
435}
436
437impl Drop for DBWithThreadModeInner {
438 fn drop(&mut self) {
439 unsafe {
440 ffi::rocksdb_close(self.inner);
441 }
442 }
443}
444
445pub type DBWithThreadMode<T> = DBCommon<T, DBWithThreadModeInner>;
450
451#[cfg(not(feature = "multi-threaded-cf"))]
474pub type DB = DBWithThreadMode<SingleThreaded>;
475
476#[cfg(feature = "multi-threaded-cf")]
477pub type DB = DBWithThreadMode<MultiThreaded>;
478
479unsafe impl<T: ThreadMode + Send, I: DBInner> Send for DBCommon<T, I> {}
483
484unsafe impl<T: ThreadMode, I: DBInner> Sync for DBCommon<T, I> {}
487
488enum AccessType<'a> {
490 ReadWrite,
491 ReadOnly { error_if_log_file_exist: bool },
492 Secondary { secondary_path: &'a Path },
493 WithTTL { ttl: Duration },
494}
495
496impl<T: ThreadMode> DBWithThreadMode<T> {
498 pub fn open_default<P: AsRef<Path>>(path: P) -> Result<Self, Error> {
500 let mut opts = Options::default();
501 opts.create_if_missing(true);
502 Self::open(&opts, path)
503 }
504
505 pub fn open<P: AsRef<Path>>(opts: &Options, path: P) -> Result<Self, Error> {
507 Self::open_cf(opts, path, None::<&str>)
508 }
509
510 pub fn open_for_read_only<P: AsRef<Path>>(
512 opts: &Options,
513 path: P,
514 error_if_log_file_exist: bool,
515 ) -> Result<Self, Error> {
516 Self::open_cf_for_read_only(opts, path, None::<&str>, error_if_log_file_exist)
517 }
518
519 pub fn open_as_secondary<P: AsRef<Path>>(
521 opts: &Options,
522 primary_path: P,
523 secondary_path: P,
524 ) -> Result<Self, Error> {
525 Self::open_cf_as_secondary(opts, primary_path, secondary_path, None::<&str>)
526 }
527
528 pub fn open_with_ttl<P: AsRef<Path>>(
533 opts: &Options,
534 path: P,
535 ttl: Duration,
536 ) -> Result<Self, Error> {
537 Self::open_cf_descriptors_with_ttl(opts, path, std::iter::empty(), ttl)
538 }
539
540 pub fn open_cf_with_ttl<P, I, N>(
544 opts: &Options,
545 path: P,
546 cfs: I,
547 ttl: Duration,
548 ) -> Result<Self, Error>
549 where
550 P: AsRef<Path>,
551 I: IntoIterator<Item = N>,
552 N: AsRef<str>,
553 {
554 let cfs = cfs
555 .into_iter()
556 .map(|name| ColumnFamilyDescriptor::new(name.as_ref(), Options::default()));
557
558 Self::open_cf_descriptors_with_ttl(opts, path, cfs, ttl)
559 }
560
561 pub fn open_cf_descriptors_with_ttl<P, I>(
575 opts: &Options,
576 path: P,
577 cfs: I,
578 ttl: Duration,
579 ) -> Result<Self, Error>
580 where
581 P: AsRef<Path>,
582 I: IntoIterator<Item = ColumnFamilyDescriptor>,
583 {
584 Self::open_cf_descriptors_internal(opts, path, cfs, &AccessType::WithTTL { ttl })
585 }
586
587 pub fn open_cf<P, I, N>(opts: &Options, path: P, cfs: I) -> Result<Self, Error>
591 where
592 P: AsRef<Path>,
593 I: IntoIterator<Item = N>,
594 N: AsRef<str>,
595 {
596 let cfs = cfs
597 .into_iter()
598 .map(|name| ColumnFamilyDescriptor::new(name.as_ref(), Options::default()));
599
600 Self::open_cf_descriptors_internal(opts, path, cfs, &AccessType::ReadWrite)
601 }
602
603 pub fn open_cf_with_opts<P, I, N>(opts: &Options, path: P, cfs: I) -> Result<Self, Error>
607 where
608 P: AsRef<Path>,
609 I: IntoIterator<Item = (N, Options)>,
610 N: AsRef<str>,
611 {
612 let cfs = cfs
613 .into_iter()
614 .map(|(name, opts)| ColumnFamilyDescriptor::new(name.as_ref(), opts));
615
616 Self::open_cf_descriptors(opts, path, cfs)
617 }
618
619 pub fn open_cf_for_read_only<P, I, N>(
623 opts: &Options,
624 path: P,
625 cfs: I,
626 error_if_log_file_exist: bool,
627 ) -> Result<Self, Error>
628 where
629 P: AsRef<Path>,
630 I: IntoIterator<Item = N>,
631 N: AsRef<str>,
632 {
633 let cfs = cfs
634 .into_iter()
635 .map(|name| ColumnFamilyDescriptor::new(name.as_ref(), Options::default()));
636
637 Self::open_cf_descriptors_internal(
638 opts,
639 path,
640 cfs,
641 &AccessType::ReadOnly {
642 error_if_log_file_exist,
643 },
644 )
645 }
646
647 pub fn open_cf_with_opts_for_read_only<P, I, N>(
651 db_opts: &Options,
652 path: P,
653 cfs: I,
654 error_if_log_file_exist: bool,
655 ) -> Result<Self, Error>
656 where
657 P: AsRef<Path>,
658 I: IntoIterator<Item = (N, Options)>,
659 N: AsRef<str>,
660 {
661 let cfs = cfs
662 .into_iter()
663 .map(|(name, cf_opts)| ColumnFamilyDescriptor::new(name.as_ref(), cf_opts));
664
665 Self::open_cf_descriptors_internal(
666 db_opts,
667 path,
668 cfs,
669 &AccessType::ReadOnly {
670 error_if_log_file_exist,
671 },
672 )
673 }
674
675 pub fn open_cf_descriptors_read_only<P, I>(
680 opts: &Options,
681 path: P,
682 cfs: I,
683 error_if_log_file_exist: bool,
684 ) -> Result<Self, Error>
685 where
686 P: AsRef<Path>,
687 I: IntoIterator<Item = ColumnFamilyDescriptor>,
688 {
689 Self::open_cf_descriptors_internal(
690 opts,
691 path,
692 cfs,
693 &AccessType::ReadOnly {
694 error_if_log_file_exist,
695 },
696 )
697 }
698
699 pub fn open_cf_as_secondary<P, I, N>(
703 opts: &Options,
704 primary_path: P,
705 secondary_path: P,
706 cfs: I,
707 ) -> Result<Self, Error>
708 where
709 P: AsRef<Path>,
710 I: IntoIterator<Item = N>,
711 N: AsRef<str>,
712 {
713 let cfs = cfs
714 .into_iter()
715 .map(|name| ColumnFamilyDescriptor::new(name.as_ref(), Options::default()));
716
717 Self::open_cf_descriptors_internal(
718 opts,
719 primary_path,
720 cfs,
721 &AccessType::Secondary {
722 secondary_path: secondary_path.as_ref(),
723 },
724 )
725 }
726
727 pub fn open_cf_descriptors_as_secondary<P, I>(
732 opts: &Options,
733 path: P,
734 secondary_path: P,
735 cfs: I,
736 ) -> Result<Self, Error>
737 where
738 P: AsRef<Path>,
739 I: IntoIterator<Item = ColumnFamilyDescriptor>,
740 {
741 Self::open_cf_descriptors_internal(
742 opts,
743 path,
744 cfs,
745 &AccessType::Secondary {
746 secondary_path: secondary_path.as_ref(),
747 },
748 )
749 }
750
751 pub fn open_cf_descriptors<P, I>(opts: &Options, path: P, cfs: I) -> Result<Self, Error>
755 where
756 P: AsRef<Path>,
757 I: IntoIterator<Item = ColumnFamilyDescriptor>,
758 {
759 Self::open_cf_descriptors_internal(opts, path, cfs, &AccessType::ReadWrite)
760 }
761
762 fn open_cf_descriptors_internal<P, I>(
764 opts: &Options,
765 path: P,
766 cfs: I,
767 access_type: &AccessType,
768 ) -> Result<Self, Error>
769 where
770 P: AsRef<Path>,
771 I: IntoIterator<Item = ColumnFamilyDescriptor>,
772 {
773 let cfs: Vec<_> = cfs.into_iter().collect();
774 let outlive = iter::once(opts.outlive.clone())
775 .chain(cfs.iter().map(|cf| cf.options.outlive.clone()))
776 .collect();
777
778 let cpath = to_cpath(&path)?;
779
780 if let Err(e) = fs::create_dir_all(&path) {
781 return Err(Error::new(format!(
782 "Failed to create RocksDB directory: `{e:?}`."
783 )));
784 }
785
786 let db: *mut ffi::rocksdb_t;
787 let mut cf_map = BTreeMap::new();
788
789 if cfs.is_empty() {
790 db = Self::open_raw(opts, &cpath, access_type)?;
791 } else {
792 let mut cfs_v = cfs;
793 if !cfs_v.iter().any(|cf| cf.name == DEFAULT_COLUMN_FAMILY_NAME) {
795 cfs_v.push(ColumnFamilyDescriptor {
796 name: String::from(DEFAULT_COLUMN_FAMILY_NAME),
797 options: Options::default(),
798 ttl: ColumnFamilyTtl::SameAsDb,
799 });
800 }
801 let c_cfs: Vec<CString> = cfs_v
804 .iter()
805 .map(|cf| CString::new(cf.name.as_bytes()).unwrap())
806 .collect();
807
808 let cfnames: Vec<_> = c_cfs.iter().map(|cf| cf.as_ptr()).collect();
809
810 let mut cfhandles: Vec<_> = cfs_v.iter().map(|_| ptr::null_mut()).collect();
812
813 let cfopts: Vec<_> = cfs_v
814 .iter()
815 .map(|cf| cf.options.inner.cast_const())
816 .collect();
817
818 db = Self::open_cf_raw(
819 opts,
820 &cpath,
821 &cfs_v,
822 &cfnames,
823 &cfopts,
824 &mut cfhandles,
825 access_type,
826 )?;
827 for handle in &cfhandles {
828 if handle.is_null() {
829 return Err(Error::new(
830 "Received null column family handle from DB.".to_owned(),
831 ));
832 }
833 }
834
835 for (cf_desc, inner) in cfs_v.iter().zip(cfhandles) {
836 cf_map.insert(cf_desc.name.clone(), inner);
837 }
838 }
839
840 if db.is_null() {
841 return Err(Error::new("Could not initialize database.".to_owned()));
842 }
843
844 Ok(Self {
845 inner: DBWithThreadModeInner { inner: db },
846 path: path.as_ref().to_path_buf(),
847 cfs: T::new_cf_map_internal(cf_map),
848 _outlive: outlive,
849 })
850 }
851
852 fn open_raw(
853 opts: &Options,
854 cpath: &CString,
855 access_type: &AccessType,
856 ) -> Result<*mut ffi::rocksdb_t, Error> {
857 let db = unsafe {
858 match *access_type {
859 AccessType::ReadOnly {
860 error_if_log_file_exist,
861 } => ffi_try!(ffi::rocksdb_open_for_read_only(
862 opts.inner,
863 cpath.as_ptr(),
864 c_uchar::from(error_if_log_file_exist),
865 )),
866 AccessType::ReadWrite => {
867 ffi_try!(ffi::rocksdb_open(opts.inner, cpath.as_ptr()))
868 }
869 AccessType::Secondary { secondary_path } => {
870 ffi_try!(ffi::rocksdb_open_as_secondary(
871 opts.inner,
872 cpath.as_ptr(),
873 to_cpath(secondary_path)?.as_ptr(),
874 ))
875 }
876 AccessType::WithTTL { ttl } => ffi_try!(ffi::rocksdb_open_with_ttl(
877 opts.inner,
878 cpath.as_ptr(),
879 ttl.as_secs() as c_int,
880 )),
881 }
882 };
883 Ok(db)
884 }
885
886 #[allow(clippy::pedantic)]
887 fn open_cf_raw(
888 opts: &Options,
889 cpath: &CString,
890 cfs_v: &[ColumnFamilyDescriptor],
891 cfnames: &[*const c_char],
892 cfopts: &[*const ffi::rocksdb_options_t],
893 cfhandles: &mut [*mut ffi::rocksdb_column_family_handle_t],
894 access_type: &AccessType,
895 ) -> Result<*mut ffi::rocksdb_t, Error> {
896 let db = unsafe {
897 match *access_type {
898 AccessType::ReadOnly {
899 error_if_log_file_exist,
900 } => ffi_try!(ffi::rocksdb_open_for_read_only_column_families(
901 opts.inner,
902 cpath.as_ptr(),
903 cfs_v.len() as c_int,
904 cfnames.as_ptr(),
905 cfopts.as_ptr(),
906 cfhandles.as_mut_ptr(),
907 c_uchar::from(error_if_log_file_exist),
908 )),
909 AccessType::ReadWrite => ffi_try!(ffi::rocksdb_open_column_families(
910 opts.inner,
911 cpath.as_ptr(),
912 cfs_v.len() as c_int,
913 cfnames.as_ptr(),
914 cfopts.as_ptr(),
915 cfhandles.as_mut_ptr(),
916 )),
917 AccessType::Secondary { secondary_path } => {
918 ffi_try!(ffi::rocksdb_open_as_secondary_column_families(
919 opts.inner,
920 cpath.as_ptr(),
921 to_cpath(secondary_path)?.as_ptr(),
922 cfs_v.len() as c_int,
923 cfnames.as_ptr(),
924 cfopts.as_ptr(),
925 cfhandles.as_mut_ptr(),
926 ))
927 }
928 AccessType::WithTTL { ttl } => {
929 let ttls: Vec<_> = cfs_v
930 .iter()
931 .map(|cf| match cf.ttl {
932 ColumnFamilyTtl::Disabled => i32::MAX,
933 ColumnFamilyTtl::Duration(duration) => duration.as_secs() as i32,
934 ColumnFamilyTtl::SameAsDb => ttl.as_secs() as i32,
935 })
936 .collect();
937
938 ffi_try!(ffi::rocksdb_open_column_families_with_ttl(
939 opts.inner,
940 cpath.as_ptr(),
941 cfs_v.len() as c_int,
942 cfnames.as_ptr(),
943 cfopts.as_ptr(),
944 cfhandles.as_mut_ptr(),
945 ttls.as_ptr(),
946 ))
947 }
948 }
949 };
950 Ok(db)
951 }
952
953 pub fn delete_range_cf_opt<K: AsRef<[u8]>>(
955 &self,
956 cf: &impl AsColumnFamilyRef,
957 from: K,
958 to: K,
959 writeopts: &WriteOptions,
960 ) -> Result<(), Error> {
961 let from = from.as_ref();
962 let to = to.as_ref();
963
964 unsafe {
965 ffi_try!(ffi::rocksdb_delete_range_cf(
966 self.inner.inner(),
967 writeopts.inner,
968 cf.inner(),
969 from.as_ptr() as *const c_char,
970 from.len() as size_t,
971 to.as_ptr() as *const c_char,
972 to.len() as size_t,
973 ));
974 Ok(())
975 }
976 }
977
978 pub fn delete_range_cf<K: AsRef<[u8]>>(
980 &self,
981 cf: &impl AsColumnFamilyRef,
982 from: K,
983 to: K,
984 ) -> Result<(), Error> {
985 DEFAULT_WRITE_OPTS.with(|opts| self.delete_range_cf_opt(cf, from, to, opts))
986 }
987
988 pub fn write_opt(&self, batch: &WriteBatch, writeopts: &WriteOptions) -> Result<(), Error> {
989 unsafe {
990 ffi_try!(ffi::rocksdb_write(
991 self.inner.inner(),
992 writeopts.inner,
993 batch.inner
994 ));
995 }
996 Ok(())
997 }
998
999 pub fn write(&self, batch: &WriteBatch) -> Result<(), Error> {
1000 DEFAULT_WRITE_OPTS.with(|opts| self.write_opt(batch, opts))
1001 }
1002
1003 pub fn write_without_wal(&self, batch: &WriteBatch) -> Result<(), Error> {
1004 let mut wo = WriteOptions::new();
1005 wo.disable_wal(true);
1006 self.write_opt(batch, &wo)
1007 }
1008
1009 pub fn write_wbwi(&self, wbwi: &WriteBatchWithIndex) -> Result<(), Error> {
1010 DEFAULT_WRITE_OPTS.with(|opts| self.write_wbwi_opt(wbwi, opts))
1011 }
1012
1013 pub fn write_wbwi_opt(
1014 &self,
1015 wbwi: &WriteBatchWithIndex,
1016 writeopts: &WriteOptions,
1017 ) -> Result<(), Error> {
1018 unsafe {
1019 ffi_try!(ffi::rocksdb_write_writebatch_wi(
1020 self.inner.inner(),
1021 writeopts.inner,
1022 wbwi.inner
1023 ));
1024
1025 Ok(())
1026 }
1027 }
1028
1029 pub fn disable_file_deletions(&self) -> Result<(), Error> {
1034 unsafe {
1035 ffi_try!(ffi::rocksdb_disable_file_deletions(self.inner.inner()));
1036 }
1037 Ok(())
1038 }
1039
1040 pub fn enable_file_deletions(&self) -> Result<(), Error> {
1052 unsafe {
1053 ffi_try!(ffi::rocksdb_enable_file_deletions(self.inner.inner()));
1054 }
1055 Ok(())
1056 }
1057}
1058
1059impl<T: ThreadMode, D: DBInner> DBCommon<T, D> {
1061 pub(crate) fn new(inner: D, cfs: T, path: PathBuf, outlive: Vec<OptionsMustOutliveDB>) -> Self {
1062 Self {
1063 inner,
1064 cfs,
1065 path,
1066 _outlive: outlive,
1067 }
1068 }
1069
1070 pub fn list_cf<P: AsRef<Path>>(opts: &Options, path: P) -> Result<Vec<String>, Error> {
1071 let cpath = to_cpath(path)?;
1072 let mut length = 0;
1073
1074 unsafe {
1075 let ptr = ffi_try!(ffi::rocksdb_list_column_families(
1076 opts.inner,
1077 cpath.as_ptr(),
1078 &raw mut length,
1079 ));
1080
1081 let vec = slice::from_raw_parts(ptr, length)
1082 .iter()
1083 .map(|ptr| from_cstr_without_free(*ptr))
1084 .collect();
1085 ffi::rocksdb_list_column_families_destroy(ptr, length);
1086 Ok(vec)
1087 }
1088 }
1089
1090 pub fn destroy<P: AsRef<Path>>(opts: &Options, path: P) -> Result<(), Error> {
1091 let cpath = to_cpath(path)?;
1092 unsafe {
1093 ffi_try!(ffi::rocksdb_destroy_db(opts.inner, cpath.as_ptr()));
1094 }
1095 Ok(())
1096 }
1097
1098 pub fn repair<P: AsRef<Path>>(opts: &Options, path: P) -> Result<(), Error> {
1099 let cpath = to_cpath(path)?;
1100 unsafe {
1101 ffi_try!(ffi::rocksdb_repair_db(opts.inner, cpath.as_ptr()));
1102 }
1103 Ok(())
1104 }
1105
1106 pub fn path(&self) -> &Path {
1107 self.path.as_path()
1108 }
1109
1110 pub fn flush_wal(&self, sync: bool) -> Result<(), Error> {
1113 unsafe {
1114 ffi_try!(ffi::rocksdb_flush_wal(
1115 self.inner.inner(),
1116 c_uchar::from(sync)
1117 ));
1118 }
1119 Ok(())
1120 }
1121
1122 pub fn flush_opt(&self, flushopts: &FlushOptions) -> Result<(), Error> {
1124 unsafe {
1125 ffi_try!(ffi::rocksdb_flush(self.inner.inner(), flushopts.inner));
1126 }
1127 Ok(())
1128 }
1129
1130 pub fn flush(&self) -> Result<(), Error> {
1132 self.flush_opt(&FlushOptions::default())
1133 }
1134
1135 pub fn flush_cf_opt(
1137 &self,
1138 cf: &impl AsColumnFamilyRef,
1139 flushopts: &FlushOptions,
1140 ) -> Result<(), Error> {
1141 unsafe {
1142 ffi_try!(ffi::rocksdb_flush_cf(
1143 self.inner.inner(),
1144 flushopts.inner,
1145 cf.inner()
1146 ));
1147 }
1148 Ok(())
1149 }
1150
1151 pub fn flush_cfs_opt(
1157 &self,
1158 cfs: &[&impl AsColumnFamilyRef],
1159 opts: &FlushOptions,
1160 ) -> Result<(), Error> {
1161 let mut cfs = cfs.iter().map(|cf| cf.inner()).collect::<Vec<_>>();
1162 unsafe {
1163 ffi_try!(ffi::rocksdb_flush_cfs(
1164 self.inner.inner(),
1165 opts.inner,
1166 cfs.as_mut_ptr(),
1167 cfs.len() as libc::c_int,
1168 ));
1169 }
1170 Ok(())
1171 }
1172
1173 pub fn flush_cf(&self, cf: &impl AsColumnFamilyRef) -> Result<(), Error> {
1176 DEFAULT_FLUSH_OPTS.with(|opts| self.flush_cf_opt(cf, opts))
1177 }
1178
1179 pub fn get_opt<K: AsRef<[u8]>>(
1183 &self,
1184 key: K,
1185 readopts: &ReadOptions,
1186 ) -> Result<Option<Vec<u8>>, Error> {
1187 self.get_pinned_opt(key, readopts)
1188 .map(|x| x.map(|v| v.as_ref().to_vec()))
1189 }
1190
1191 pub fn get<K: AsRef<[u8]>>(&self, key: K) -> Result<Option<Vec<u8>>, Error> {
1195 DEFAULT_READ_OPTS.with(|opts| self.get_opt(key.as_ref(), opts))
1196 }
1197
1198 pub fn get_cf_opt<K: AsRef<[u8]>>(
1202 &self,
1203 cf: &impl AsColumnFamilyRef,
1204 key: K,
1205 readopts: &ReadOptions,
1206 ) -> Result<Option<Vec<u8>>, Error> {
1207 self.get_pinned_cf_opt(cf, key, readopts)
1208 .map(|x| x.map(|v| v.as_ref().to_vec()))
1209 }
1210
1211 pub fn get_cf<K: AsRef<[u8]>>(
1215 &self,
1216 cf: &impl AsColumnFamilyRef,
1217 key: K,
1218 ) -> Result<Option<Vec<u8>>, Error> {
1219 DEFAULT_READ_OPTS.with(|opts| self.get_cf_opt(cf, key.as_ref(), opts))
1220 }
1221
1222 pub fn get_pinned_opt<K: AsRef<[u8]>>(
1225 &'_ self,
1226 key: K,
1227 readopts: &ReadOptions,
1228 ) -> Result<Option<DBPinnableSlice<'_>>, Error> {
1229 if readopts.inner.is_null() {
1230 return Err(Error::new(
1231 "Unable to create RocksDB read options. This is a fairly trivial call, and its \
1232 failure may be indicative of a mis-compiled or mis-loaded RocksDB library."
1233 .to_owned(),
1234 ));
1235 }
1236
1237 let key = key.as_ref();
1238 unsafe {
1239 let val = ffi_try!(ffi::rocksdb_get_pinned(
1240 self.inner.inner(),
1241 readopts.inner,
1242 key.as_ptr() as *const c_char,
1243 key.len() as size_t,
1244 ));
1245 if val.is_null() {
1246 Ok(None)
1247 } else {
1248 Ok(Some(DBPinnableSlice::from_c(val)))
1249 }
1250 }
1251 }
1252
1253 pub fn get_pinned<K: AsRef<[u8]>>(
1257 &'_ self,
1258 key: K,
1259 ) -> Result<Option<DBPinnableSlice<'_>>, Error> {
1260 DEFAULT_READ_OPTS.with(|opts| self.get_pinned_opt(key, opts))
1261 }
1262
1263 pub fn get_pinned_cf_opt<K: AsRef<[u8]>>(
1267 &'_ self,
1268 cf: &impl AsColumnFamilyRef,
1269 key: K,
1270 readopts: &ReadOptions,
1271 ) -> Result<Option<DBPinnableSlice<'_>>, Error> {
1272 if readopts.inner.is_null() {
1273 return Err(Error::new(
1274 "Unable to create RocksDB read options. This is a fairly trivial call, and its \
1275 failure may be indicative of a mis-compiled or mis-loaded RocksDB library."
1276 .to_owned(),
1277 ));
1278 }
1279
1280 let key = key.as_ref();
1281 unsafe {
1282 let val = ffi_try!(ffi::rocksdb_get_pinned_cf(
1283 self.inner.inner(),
1284 readopts.inner,
1285 cf.inner(),
1286 key.as_ptr() as *const c_char,
1287 key.len() as size_t,
1288 ));
1289 if val.is_null() {
1290 Ok(None)
1291 } else {
1292 Ok(Some(DBPinnableSlice::from_c(val)))
1293 }
1294 }
1295 }
1296
1297 pub fn get_pinned_cf<K: AsRef<[u8]>>(
1301 &'_ self,
1302 cf: &impl AsColumnFamilyRef,
1303 key: K,
1304 ) -> Result<Option<DBPinnableSlice<'_>>, Error> {
1305 DEFAULT_READ_OPTS.with(|opts| self.get_pinned_cf_opt(cf, key, opts))
1306 }
1307
1308 pub fn get_into_buffer<K: AsRef<[u8]>>(
1378 &self,
1379 key: K,
1380 buffer: &mut [u8],
1381 ) -> Result<GetIntoBufferResult, Error> {
1382 DEFAULT_READ_OPTS.with(|opts| self.get_into_buffer_opt(key, buffer, opts))
1383 }
1384
1385 pub fn get_into_buffer_opt<K: AsRef<[u8]>>(
1392 &self,
1393 key: K,
1394 buffer: &mut [u8],
1395 readopts: &ReadOptions,
1396 ) -> Result<GetIntoBufferResult, Error> {
1397 if readopts.inner.is_null() {
1398 return Err(Error::new(
1399 "Unable to create RocksDB read options. This is a fairly trivial call, and its \
1400 failure may be indicative of a mis-compiled or mis-loaded RocksDB library."
1401 .to_owned(),
1402 ));
1403 }
1404
1405 let key = key.as_ref();
1406 let mut val_len: size_t = 0;
1407 let mut found: c_uchar = 0;
1408
1409 unsafe {
1410 let success = ffi_try!(ffi::rocksdb_get_into_buffer(
1411 self.inner.inner(),
1412 readopts.inner,
1413 key.as_ptr() as *const c_char,
1414 key.len() as size_t,
1415 buffer.as_mut_ptr() as *mut c_char,
1416 buffer.len() as size_t,
1417 &raw mut val_len,
1418 &raw mut found,
1419 ));
1420
1421 if found == 0 {
1422 Ok(GetIntoBufferResult::NotFound)
1423 } else if success != 0 {
1424 Ok(GetIntoBufferResult::Found(val_len))
1425 } else {
1426 Ok(GetIntoBufferResult::BufferTooSmall(val_len))
1427 }
1428 }
1429 }
1430
1431 pub fn get_into_buffer_cf<K: AsRef<[u8]>>(
1442 &self,
1443 cf: &impl AsColumnFamilyRef,
1444 key: K,
1445 buffer: &mut [u8],
1446 ) -> Result<GetIntoBufferResult, Error> {
1447 DEFAULT_READ_OPTS.with(|opts| self.get_into_buffer_cf_opt(cf, key, buffer, opts))
1448 }
1449
1450 pub fn get_into_buffer_cf_opt<K: AsRef<[u8]>>(
1456 &self,
1457 cf: &impl AsColumnFamilyRef,
1458 key: K,
1459 buffer: &mut [u8],
1460 readopts: &ReadOptions,
1461 ) -> Result<GetIntoBufferResult, Error> {
1462 if readopts.inner.is_null() {
1463 return Err(Error::new(
1464 "Unable to create RocksDB read options. This is a fairly trivial call, and its \
1465 failure may be indicative of a mis-compiled or mis-loaded RocksDB library."
1466 .to_owned(),
1467 ));
1468 }
1469
1470 let key = key.as_ref();
1471 let mut val_len: size_t = 0;
1472 let mut found: c_uchar = 0;
1473
1474 unsafe {
1475 let success = ffi_try!(ffi::rocksdb_get_into_buffer_cf(
1476 self.inner.inner(),
1477 readopts.inner,
1478 cf.inner(),
1479 key.as_ptr() as *const c_char,
1480 key.len() as size_t,
1481 buffer.as_mut_ptr() as *mut c_char,
1482 buffer.len() as size_t,
1483 &raw mut val_len,
1484 &raw mut found,
1485 ));
1486
1487 if found == 0 {
1488 Ok(GetIntoBufferResult::NotFound)
1489 } else if success != 0 {
1490 Ok(GetIntoBufferResult::Found(val_len))
1491 } else {
1492 Ok(GetIntoBufferResult::BufferTooSmall(val_len))
1493 }
1494 }
1495 }
1496
1497 pub fn multi_get<K, I>(&self, keys: I) -> Vec<Result<Option<Vec<u8>>, Error>>
1499 where
1500 K: AsRef<[u8]>,
1501 I: IntoIterator<Item = K>,
1502 {
1503 DEFAULT_READ_OPTS.with(|opts| self.multi_get_opt(keys, opts))
1504 }
1505
1506 pub fn multi_get_opt<K, I>(
1508 &self,
1509 keys: I,
1510 readopts: &ReadOptions,
1511 ) -> Vec<Result<Option<Vec<u8>>, Error>>
1512 where
1513 K: AsRef<[u8]>,
1514 I: IntoIterator<Item = K>,
1515 {
1516 let owned_keys: Vec<K> = keys.into_iter().collect();
1517 let (ptr_keys, keys_sizes): (Vec<*const c_char>, Vec<usize>) = owned_keys
1518 .iter()
1519 .map(|k| {
1520 let key = k.as_ref();
1521 (key.as_ptr() as *const c_char, key.len())
1522 })
1523 .unzip();
1524
1525 let mut values: Vec<*mut c_char> = Vec::with_capacity(ptr_keys.len());
1526 let mut values_sizes: Vec<usize> = Vec::with_capacity(ptr_keys.len());
1527 let mut errors: Vec<*mut c_char> = Vec::with_capacity(ptr_keys.len());
1528 unsafe {
1529 ffi::rocksdb_multi_get(
1530 self.inner.inner(),
1531 readopts.inner,
1532 ptr_keys.len(),
1533 ptr_keys.as_ptr(),
1534 keys_sizes.as_ptr(),
1535 values.as_mut_ptr(),
1536 values_sizes.as_mut_ptr(),
1537 errors.as_mut_ptr(),
1538 );
1539 }
1540
1541 unsafe {
1542 values.set_len(ptr_keys.len());
1543 values_sizes.set_len(ptr_keys.len());
1544 errors.set_len(ptr_keys.len());
1545 }
1546
1547 convert_values(values, values_sizes, errors)
1548 }
1549
1550 pub fn multi_get_pinned<K, I>(
1555 &'_ self,
1556 keys: I,
1557 ) -> Vec<Result<Option<DBPinnableSlice<'_>>, Error>>
1558 where
1559 K: AsRef<[u8]>,
1560 I: IntoIterator<Item = K>,
1561 {
1562 DEFAULT_READ_OPTS.with(|opts| self.multi_get_pinned_opt(keys, opts))
1563 }
1564
1565 pub fn multi_get_pinned_opt<K, I>(
1570 &'_ self,
1571 keys: I,
1572 readopts: &ReadOptions,
1573 ) -> Vec<Result<Option<DBPinnableSlice<'_>>, Error>>
1574 where
1575 K: AsRef<[u8]>,
1576 I: IntoIterator<Item = K>,
1577 {
1578 keys.into_iter()
1579 .map(|k| self.get_pinned_opt(k, readopts))
1580 .collect()
1581 }
1582
1583 pub fn multi_get_pinned_cf<'a, 'b: 'a, K, I, W>(
1586 &'a self,
1587 keys: I,
1588 ) -> Vec<Result<Option<DBPinnableSlice<'a>>, Error>>
1589 where
1590 K: AsRef<[u8]>,
1591 I: IntoIterator<Item = (&'b W, K)>,
1592 W: 'b + AsColumnFamilyRef,
1593 {
1594 DEFAULT_READ_OPTS.with(|opts| self.multi_get_pinned_cf_opt(keys, opts))
1595 }
1596
1597 pub fn multi_get_pinned_cf_opt<'a, 'b: 'a, K, I, W>(
1600 &'a self,
1601 keys: I,
1602 readopts: &ReadOptions,
1603 ) -> Vec<Result<Option<DBPinnableSlice<'a>>, Error>>
1604 where
1605 K: AsRef<[u8]>,
1606 I: IntoIterator<Item = (&'b W, K)>,
1607 W: 'b + AsColumnFamilyRef,
1608 {
1609 keys.into_iter()
1610 .map(|(cf, k)| self.get_pinned_cf_opt(cf, k, readopts))
1611 .collect()
1612 }
1613
1614 pub fn multi_get_cf<'a, 'b: 'a, K, I, W>(
1616 &'a self,
1617 keys: I,
1618 ) -> Vec<Result<Option<Vec<u8>>, Error>>
1619 where
1620 K: AsRef<[u8]>,
1621 I: IntoIterator<Item = (&'b W, K)>,
1622 W: 'b + AsColumnFamilyRef,
1623 {
1624 DEFAULT_READ_OPTS.with(|opts| self.multi_get_cf_opt(keys, opts))
1625 }
1626
1627 pub fn multi_get_cf_opt<'a, 'b: 'a, K, I, W>(
1629 &'a self,
1630 keys: I,
1631 readopts: &ReadOptions,
1632 ) -> Vec<Result<Option<Vec<u8>>, Error>>
1633 where
1634 K: AsRef<[u8]>,
1635 I: IntoIterator<Item = (&'b W, K)>,
1636 W: 'b + AsColumnFamilyRef,
1637 {
1638 let cfs_and_owned_keys: Vec<(&'b W, K)> = keys.into_iter().collect();
1639 let (ptr_keys, keys_sizes): (Vec<*const c_char>, Vec<usize>) = cfs_and_owned_keys
1640 .iter()
1641 .map(|(_, k)| {
1642 let key = k.as_ref();
1643 (key.as_ptr() as *const c_char, key.len())
1644 })
1645 .unzip();
1646 let ptr_cfs: Vec<*const ffi::rocksdb_column_family_handle_t> = cfs_and_owned_keys
1647 .iter()
1648 .map(|(c, _)| c.inner().cast_const())
1649 .collect();
1650 let mut values: Vec<*mut c_char> = Vec::with_capacity(ptr_keys.len());
1651 let mut values_sizes: Vec<usize> = Vec::with_capacity(ptr_keys.len());
1652 let mut errors: Vec<*mut c_char> = Vec::with_capacity(ptr_keys.len());
1653 unsafe {
1654 ffi::rocksdb_multi_get_cf(
1655 self.inner.inner(),
1656 readopts.inner,
1657 ptr_cfs.as_ptr(),
1658 ptr_keys.len(),
1659 ptr_keys.as_ptr(),
1660 keys_sizes.as_ptr(),
1661 values.as_mut_ptr(),
1662 values_sizes.as_mut_ptr(),
1663 errors.as_mut_ptr(),
1664 );
1665 }
1666
1667 unsafe {
1668 values.set_len(ptr_keys.len());
1669 values_sizes.set_len(ptr_keys.len());
1670 errors.set_len(ptr_keys.len());
1671 }
1672
1673 convert_values(values, values_sizes, errors)
1674 }
1675
1676 pub fn batched_multi_get_cf<'a, K, I>(
1680 &'_ self,
1681 cf: &impl AsColumnFamilyRef,
1682 keys: I,
1683 sorted_input: bool,
1684 ) -> Vec<Result<Option<DBPinnableSlice<'_>>, Error>>
1685 where
1686 K: AsRef<[u8]> + 'a + ?Sized,
1687 I: IntoIterator<Item = &'a K>,
1688 {
1689 DEFAULT_READ_OPTS.with(|opts| self.batched_multi_get_cf_opt(cf, keys, sorted_input, opts))
1690 }
1691
1692 pub fn batched_multi_get_cf_opt<'a, K, I>(
1696 &'_ self,
1697 cf: &impl AsColumnFamilyRef,
1698 keys: I,
1699 sorted_input: bool,
1700 readopts: &ReadOptions,
1701 ) -> Vec<Result<Option<DBPinnableSlice<'_>>, Error>>
1702 where
1703 K: AsRef<[u8]> + 'a + ?Sized,
1704 I: IntoIterator<Item = &'a K>,
1705 {
1706 let (ptr_keys, keys_sizes): (Vec<_>, Vec<_>) = keys
1707 .into_iter()
1708 .map(|k| {
1709 let k = k.as_ref();
1710 (k.as_ptr() as *const c_char, k.len())
1711 })
1712 .unzip();
1713
1714 let mut pinned_values = vec![ptr::null_mut(); ptr_keys.len()];
1715 let mut errors = vec![ptr::null_mut(); ptr_keys.len()];
1716
1717 unsafe {
1718 ffi::rocksdb_batched_multi_get_cf(
1719 self.inner.inner(),
1720 readopts.inner,
1721 cf.inner(),
1722 ptr_keys.len(),
1723 ptr_keys.as_ptr(),
1724 keys_sizes.as_ptr(),
1725 pinned_values.as_mut_ptr(),
1726 errors.as_mut_ptr(),
1727 sorted_input,
1728 );
1729 pinned_values
1730 .into_iter()
1731 .zip(errors)
1732 .map(|(v, e)| {
1733 if e.is_null() {
1734 if v.is_null() {
1735 Ok(None)
1736 } else {
1737 Ok(Some(DBPinnableSlice::from_c(v)))
1738 }
1739 } else {
1740 Err(convert_rocksdb_error(e))
1741 }
1742 })
1743 .collect()
1744 }
1745 }
1746
1747 pub fn batched_multi_get_cf_slice<'a, K, I>(
1804 &'_ self,
1805 cf: &impl AsColumnFamilyRef,
1806 keys: I,
1807 sorted_input: bool,
1808 ) -> Vec<Result<Option<DBPinnableSlice<'_>>, Error>>
1809 where
1810 K: AsRef<[u8]> + 'a + ?Sized,
1811 I: IntoIterator<Item = &'a K>,
1812 {
1813 DEFAULT_READ_OPTS
1814 .with(|opts| self.batched_multi_get_cf_slice_opt(cf, keys, sorted_input, opts))
1815 }
1816
1817 pub fn batched_multi_get_cf_slice_opt<'a, K, I>(
1825 &'_ self,
1826 cf: &impl AsColumnFamilyRef,
1827 keys: I,
1828 sorted_input: bool,
1829 readopts: &ReadOptions,
1830 ) -> Vec<Result<Option<DBPinnableSlice<'_>>, Error>>
1831 where
1832 K: AsRef<[u8]> + 'a + ?Sized,
1833 I: IntoIterator<Item = &'a K>,
1834 {
1835 let slices: Vec<ffi::rocksdb_slice_t> = keys
1837 .into_iter()
1838 .map(|k| {
1839 let k = k.as_ref();
1840 ffi::rocksdb_slice_t {
1841 data: k.as_ptr() as *const c_char,
1842 size: k.len(),
1843 }
1844 })
1845 .collect();
1846
1847 if slices.is_empty() {
1848 return Vec::new();
1849 }
1850
1851 let mut pinned_values = vec![ptr::null_mut(); slices.len()];
1852 let mut errors = vec![ptr::null_mut(); slices.len()];
1853
1854 unsafe {
1855 ffi::rocksdb_batched_multi_get_cf_slice(
1856 self.inner.inner(),
1857 readopts.inner,
1858 cf.inner(),
1859 slices.len(),
1860 slices.as_ptr(),
1861 pinned_values.as_mut_ptr(),
1862 errors.as_mut_ptr(),
1863 sorted_input,
1864 );
1865 pinned_values
1866 .into_iter()
1867 .zip(errors)
1868 .map(|(v, e)| {
1869 if e.is_null() {
1870 if v.is_null() {
1871 Ok(None)
1872 } else {
1873 Ok(Some(DBPinnableSlice::from_c(v)))
1874 }
1875 } else {
1876 Err(convert_rocksdb_error(e))
1877 }
1878 })
1879 .collect()
1880 }
1881 }
1882
1883 pub fn key_may_exist<K: AsRef<[u8]>>(&self, key: K) -> bool {
1886 DEFAULT_READ_OPTS.with(|opts| self.key_may_exist_opt(key, opts))
1887 }
1888
1889 pub fn key_may_exist_opt<K: AsRef<[u8]>>(&self, key: K, readopts: &ReadOptions) -> bool {
1892 let key = key.as_ref();
1893 unsafe {
1894 0 != ffi::rocksdb_key_may_exist(
1895 self.inner.inner(),
1896 readopts.inner,
1897 key.as_ptr() as *const c_char,
1898 key.len() as size_t,
1899 ptr::null_mut(), ptr::null_mut(), ptr::null(), 0, ptr::null_mut(), )
1905 }
1906 }
1907
1908 pub fn key_may_exist_cf<K: AsRef<[u8]>>(&self, cf: &impl AsColumnFamilyRef, key: K) -> bool {
1911 DEFAULT_READ_OPTS.with(|opts| self.key_may_exist_cf_opt(cf, key, opts))
1912 }
1913
1914 pub fn key_may_exist_cf_opt<K: AsRef<[u8]>>(
1917 &self,
1918 cf: &impl AsColumnFamilyRef,
1919 key: K,
1920 readopts: &ReadOptions,
1921 ) -> bool {
1922 let key = key.as_ref();
1923 0 != unsafe {
1924 ffi::rocksdb_key_may_exist_cf(
1925 self.inner.inner(),
1926 readopts.inner,
1927 cf.inner(),
1928 key.as_ptr() as *const c_char,
1929 key.len() as size_t,
1930 ptr::null_mut(), ptr::null_mut(), ptr::null(), 0, ptr::null_mut(), )
1936 }
1937 }
1938
1939 pub fn key_may_exist_cf_opt_value<K: AsRef<[u8]>>(
1946 &self,
1947 cf: &impl AsColumnFamilyRef,
1948 key: K,
1949 readopts: &ReadOptions,
1950 ) -> (bool, Option<CSlice>) {
1951 let key = key.as_ref();
1952 let mut val: *mut c_char = ptr::null_mut();
1953 let mut val_len: usize = 0;
1954 let mut value_found: c_uchar = 0;
1955 let may_exists = 0
1956 != unsafe {
1957 ffi::rocksdb_key_may_exist_cf(
1958 self.inner.inner(),
1959 readopts.inner,
1960 cf.inner(),
1961 key.as_ptr() as *const c_char,
1962 key.len() as size_t,
1963 &raw mut val, &raw mut val_len, ptr::null(), 0, &raw mut value_found, )
1969 };
1970 if may_exists && value_found != 0 {
1973 (
1974 may_exists,
1975 Some(unsafe { CSlice::from_raw_parts(val, val_len) }),
1976 )
1977 } else {
1978 (may_exists, None)
1979 }
1980 }
1981
1982 fn create_inner_cf_handle(
1983 &self,
1984 name: impl CStrLike,
1985 opts: &Options,
1986 ) -> Result<*mut ffi::rocksdb_column_family_handle_t, Error> {
1987 let cf_name = name.bake().map_err(|err| {
1988 Error::new(format!(
1989 "Failed to convert path to CString when creating cf: {err}"
1990 ))
1991 })?;
1992
1993 let mut err: *mut ::libc::c_char = ::std::ptr::null_mut();
1996 let cf_handle = unsafe {
1997 ffi::rocksdb_create_column_family(
1998 self.inner.inner(),
1999 opts.inner,
2000 cf_name.as_ptr(),
2001 &raw mut err,
2002 )
2003 };
2004 if !err.is_null() {
2005 if !cf_handle.is_null() {
2006 unsafe { ffi::rocksdb_column_family_handle_destroy(cf_handle) };
2007 }
2008 return Err(convert_rocksdb_error(err));
2009 }
2010 Ok(cf_handle)
2011 }
2012
2013 pub fn iterator<'a: 'b, 'b>(
2014 &'a self,
2015 mode: IteratorMode,
2016 ) -> DBIteratorWithThreadMode<'b, Self> {
2017 let readopts = ReadOptions::default();
2018 self.iterator_opt(mode, readopts)
2019 }
2020
2021 pub fn iterator_opt<'a: 'b, 'b>(
2022 &'a self,
2023 mode: IteratorMode,
2024 readopts: ReadOptions,
2025 ) -> DBIteratorWithThreadMode<'b, Self> {
2026 DBIteratorWithThreadMode::new(self, readopts, mode)
2027 }
2028
2029 pub fn iterator_cf_opt<'a: 'b, 'b>(
2032 &'a self,
2033 cf_handle: &impl AsColumnFamilyRef,
2034 readopts: ReadOptions,
2035 mode: IteratorMode,
2036 ) -> DBIteratorWithThreadMode<'b, Self> {
2037 DBIteratorWithThreadMode::new_cf(self, cf_handle.inner(), readopts, mode)
2038 }
2039
2040 pub fn full_iterator<'a: 'b, 'b>(
2044 &'a self,
2045 mode: IteratorMode,
2046 ) -> DBIteratorWithThreadMode<'b, Self> {
2047 let mut opts = ReadOptions::default();
2048 opts.set_total_order_seek(true);
2049 DBIteratorWithThreadMode::new(self, opts, mode)
2050 }
2051
2052 pub fn prefix_iterator<'a: 'b, 'b, P: AsRef<[u8]>>(
2053 &'a self,
2054 prefix: P,
2055 ) -> DBIteratorWithThreadMode<'b, Self> {
2056 let mut opts = ReadOptions::default();
2057 opts.set_prefix_same_as_start(true);
2058 DBIteratorWithThreadMode::new(
2059 self,
2060 opts,
2061 IteratorMode::From(prefix.as_ref(), Direction::Forward),
2062 )
2063 }
2064
2065 pub fn iterator_cf<'a: 'b, 'b>(
2066 &'a self,
2067 cf_handle: &impl AsColumnFamilyRef,
2068 mode: IteratorMode,
2069 ) -> DBIteratorWithThreadMode<'b, Self> {
2070 let opts = ReadOptions::default();
2071 DBIteratorWithThreadMode::new_cf(self, cf_handle.inner(), opts, mode)
2072 }
2073
2074 pub fn full_iterator_cf<'a: 'b, 'b>(
2075 &'a self,
2076 cf_handle: &impl AsColumnFamilyRef,
2077 mode: IteratorMode,
2078 ) -> DBIteratorWithThreadMode<'b, Self> {
2079 let mut opts = ReadOptions::default();
2080 opts.set_total_order_seek(true);
2081 DBIteratorWithThreadMode::new_cf(self, cf_handle.inner(), opts, mode)
2082 }
2083
2084 pub fn prefix_iterator_cf<'a, P: AsRef<[u8]>>(
2085 &'a self,
2086 cf_handle: &impl AsColumnFamilyRef,
2087 prefix: P,
2088 ) -> DBIteratorWithThreadMode<'a, Self> {
2089 let mut opts = ReadOptions::default();
2090 opts.set_prefix_same_as_start(true);
2091 DBIteratorWithThreadMode::<'a, Self>::new_cf(
2092 self,
2093 cf_handle.inner(),
2094 opts,
2095 IteratorMode::From(prefix.as_ref(), Direction::Forward),
2096 )
2097 }
2098
2099 pub fn prefix_exists<P: AsRef<[u8]>>(&self, prefix: P) -> Result<bool, Error> {
2106 let p = prefix.as_ref();
2107 PREFIX_READ_OPTS.with(|rc| {
2108 let mut opts = rc.borrow_mut();
2109 opts.set_iterate_range(crate::PrefixRange(p));
2110 self.prefix_exists_opt(p, &opts)
2111 })
2112 }
2113
2114 pub fn prefix_exists_opt<P: AsRef<[u8]>>(
2117 &self,
2118 prefix: P,
2119 readopts: &ReadOptions,
2120 ) -> Result<bool, Error> {
2121 let prefix = prefix.as_ref();
2122 let iter = unsafe { self.create_iterator(readopts) };
2123 let res = unsafe {
2124 ffi::rocksdb_iter_seek(
2125 iter,
2126 prefix.as_ptr() as *const c_char,
2127 prefix.len() as size_t,
2128 );
2129 if ffi::rocksdb_iter_valid(iter) != 0 {
2130 let mut key_len: size_t = 0;
2131 let key_ptr = ffi::rocksdb_iter_key(iter, &raw mut key_len);
2132 let key = slice::from_raw_parts(key_ptr.cast::<u8>(), key_len as usize);
2133 Ok(key.starts_with(prefix))
2134 } else if let Err(e) = (|| {
2135 ffi_try!(ffi::rocksdb_iter_get_error(iter));
2137 Ok::<(), Error>(())
2138 })() {
2139 Err(e)
2140 } else {
2141 Ok(false)
2142 }
2143 };
2144 unsafe { ffi::rocksdb_iter_destroy(iter) };
2145 res
2146 }
2147
2148 pub fn prefix_prober(&self) -> PrefixProber<'_, Self> {
2156 let mut opts = ReadOptions::default();
2157 opts.set_prefix_same_as_start(true);
2158 PrefixProber {
2159 raw: DBRawIteratorWithThreadMode::new(self, opts),
2160 }
2161 }
2162
2163 pub fn prefix_prober_with_opts(&self, readopts: ReadOptions) -> PrefixProber<'_, Self> {
2170 PrefixProber {
2171 raw: DBRawIteratorWithThreadMode::new(self, readopts),
2172 }
2173 }
2174
2175 pub fn prefix_prober_cf(&self, cf_handle: &impl AsColumnFamilyRef) -> PrefixProber<'_, Self> {
2178 let mut opts = ReadOptions::default();
2179 opts.set_prefix_same_as_start(true);
2180 PrefixProber {
2181 raw: DBRawIteratorWithThreadMode::new_cf(self, cf_handle.inner(), opts),
2182 }
2183 }
2184
2185 pub fn prefix_prober_cf_with_opts(
2190 &self,
2191 cf_handle: &impl AsColumnFamilyRef,
2192 readopts: ReadOptions,
2193 ) -> PrefixProber<'_, Self> {
2194 PrefixProber {
2195 raw: DBRawIteratorWithThreadMode::new_cf(self, cf_handle.inner(), readopts),
2196 }
2197 }
2198
2199 pub fn prefix_exists_cf<P: AsRef<[u8]>>(
2205 &self,
2206 cf_handle: &impl AsColumnFamilyRef,
2207 prefix: P,
2208 ) -> Result<bool, Error> {
2209 let p = prefix.as_ref();
2210 PREFIX_READ_OPTS.with(|rc| {
2211 let mut opts = rc.borrow_mut();
2212 opts.set_iterate_range(crate::PrefixRange(p));
2213 self.prefix_exists_cf_opt(cf_handle, p, &opts)
2214 })
2215 }
2216
2217 pub fn prefix_exists_cf_opt<P: AsRef<[u8]>>(
2220 &self,
2221 cf_handle: &impl AsColumnFamilyRef,
2222 prefix: P,
2223 readopts: &ReadOptions,
2224 ) -> Result<bool, Error> {
2225 let prefix = prefix.as_ref();
2226 let iter = unsafe { self.create_iterator_cf(cf_handle.inner(), readopts) };
2227 let res = unsafe {
2228 ffi::rocksdb_iter_seek(
2229 iter,
2230 prefix.as_ptr() as *const c_char,
2231 prefix.len() as size_t,
2232 );
2233 if ffi::rocksdb_iter_valid(iter) != 0 {
2234 let mut key_len: size_t = 0;
2235 let key_ptr = ffi::rocksdb_iter_key(iter, &raw mut key_len);
2236 let key = slice::from_raw_parts(key_ptr.cast::<u8>(), key_len as usize);
2237 Ok(key.starts_with(prefix))
2238 } else if let Err(e) = (|| {
2239 ffi_try!(ffi::rocksdb_iter_get_error(iter));
2240 Ok::<(), Error>(())
2241 })() {
2242 Err(e)
2243 } else {
2244 Ok(false)
2245 }
2246 };
2247 unsafe { ffi::rocksdb_iter_destroy(iter) };
2248 res
2249 }
2250
2251 pub fn raw_iterator<'a: 'b, 'b>(&'a self) -> DBRawIteratorWithThreadMode<'b, Self> {
2253 let opts = ReadOptions::default();
2254 DBRawIteratorWithThreadMode::new(self, opts)
2255 }
2256
2257 pub fn raw_iterator_cf<'a: 'b, 'b>(
2259 &'a self,
2260 cf_handle: &impl AsColumnFamilyRef,
2261 ) -> DBRawIteratorWithThreadMode<'b, Self> {
2262 let opts = ReadOptions::default();
2263 DBRawIteratorWithThreadMode::new_cf(self, cf_handle.inner(), opts)
2264 }
2265
2266 pub fn raw_iterator_opt<'a: 'b, 'b>(
2268 &'a self,
2269 readopts: ReadOptions,
2270 ) -> DBRawIteratorWithThreadMode<'b, Self> {
2271 DBRawIteratorWithThreadMode::new(self, readopts)
2272 }
2273
2274 pub fn raw_iterator_cf_opt<'a: 'b, 'b>(
2276 &'a self,
2277 cf_handle: &impl AsColumnFamilyRef,
2278 readopts: ReadOptions,
2279 ) -> DBRawIteratorWithThreadMode<'b, Self> {
2280 DBRawIteratorWithThreadMode::new_cf(self, cf_handle.inner(), readopts)
2281 }
2282
2283 pub fn snapshot(&'_ self) -> SnapshotWithThreadMode<'_, Self> {
2284 SnapshotWithThreadMode::<Self>::new(self)
2285 }
2286
2287 pub fn put_opt<K, V>(&self, key: K, value: V, writeopts: &WriteOptions) -> Result<(), Error>
2288 where
2289 K: AsRef<[u8]>,
2290 V: AsRef<[u8]>,
2291 {
2292 let key = key.as_ref();
2293 let value = value.as_ref();
2294
2295 unsafe {
2296 ffi_try!(ffi::rocksdb_put(
2297 self.inner.inner(),
2298 writeopts.inner,
2299 key.as_ptr() as *const c_char,
2300 key.len() as size_t,
2301 value.as_ptr() as *const c_char,
2302 value.len() as size_t,
2303 ));
2304 Ok(())
2305 }
2306 }
2307
2308 pub fn put_cf_opt<K, V>(
2309 &self,
2310 cf: &impl AsColumnFamilyRef,
2311 key: K,
2312 value: V,
2313 writeopts: &WriteOptions,
2314 ) -> Result<(), Error>
2315 where
2316 K: AsRef<[u8]>,
2317 V: AsRef<[u8]>,
2318 {
2319 let key = key.as_ref();
2320 let value = value.as_ref();
2321
2322 unsafe {
2323 ffi_try!(ffi::rocksdb_put_cf(
2324 self.inner.inner(),
2325 writeopts.inner,
2326 cf.inner(),
2327 key.as_ptr() as *const c_char,
2328 key.len() as size_t,
2329 value.as_ptr() as *const c_char,
2330 value.len() as size_t,
2331 ));
2332 Ok(())
2333 }
2334 }
2335
2336 pub fn put_with_ts_opt<K, V, S>(
2343 &self,
2344 key: K,
2345 ts: S,
2346 value: V,
2347 writeopts: &WriteOptions,
2348 ) -> Result<(), Error>
2349 where
2350 K: AsRef<[u8]>,
2351 V: AsRef<[u8]>,
2352 S: AsRef<[u8]>,
2353 {
2354 let key = key.as_ref();
2355 let value = value.as_ref();
2356 let ts = ts.as_ref();
2357 unsafe {
2358 ffi_try!(ffi::rocksdb_put_with_ts(
2359 self.inner.inner(),
2360 writeopts.inner,
2361 key.as_ptr() as *const c_char,
2362 key.len() as size_t,
2363 ts.as_ptr() as *const c_char,
2364 ts.len() as size_t,
2365 value.as_ptr() as *const c_char,
2366 value.len() as size_t,
2367 ));
2368 Ok(())
2369 }
2370 }
2371
2372 pub fn put_cf_with_ts_opt<K, V, S>(
2379 &self,
2380 cf: &impl AsColumnFamilyRef,
2381 key: K,
2382 ts: S,
2383 value: V,
2384 writeopts: &WriteOptions,
2385 ) -> Result<(), Error>
2386 where
2387 K: AsRef<[u8]>,
2388 V: AsRef<[u8]>,
2389 S: AsRef<[u8]>,
2390 {
2391 let key = key.as_ref();
2392 let value = value.as_ref();
2393 let ts = ts.as_ref();
2394 unsafe {
2395 ffi_try!(ffi::rocksdb_put_cf_with_ts(
2396 self.inner.inner(),
2397 writeopts.inner,
2398 cf.inner(),
2399 key.as_ptr() as *const c_char,
2400 key.len() as size_t,
2401 ts.as_ptr() as *const c_char,
2402 ts.len() as size_t,
2403 value.as_ptr() as *const c_char,
2404 value.len() as size_t,
2405 ));
2406 Ok(())
2407 }
2408 }
2409
2410 pub fn merge_opt<K, V>(&self, key: K, value: V, writeopts: &WriteOptions) -> Result<(), Error>
2411 where
2412 K: AsRef<[u8]>,
2413 V: AsRef<[u8]>,
2414 {
2415 let key = key.as_ref();
2416 let value = value.as_ref();
2417
2418 unsafe {
2419 ffi_try!(ffi::rocksdb_merge(
2420 self.inner.inner(),
2421 writeopts.inner,
2422 key.as_ptr() as *const c_char,
2423 key.len() as size_t,
2424 value.as_ptr() as *const c_char,
2425 value.len() as size_t,
2426 ));
2427 Ok(())
2428 }
2429 }
2430
2431 pub fn merge_cf_opt<K, V>(
2432 &self,
2433 cf: &impl AsColumnFamilyRef,
2434 key: K,
2435 value: V,
2436 writeopts: &WriteOptions,
2437 ) -> Result<(), Error>
2438 where
2439 K: AsRef<[u8]>,
2440 V: AsRef<[u8]>,
2441 {
2442 let key = key.as_ref();
2443 let value = value.as_ref();
2444
2445 unsafe {
2446 ffi_try!(ffi::rocksdb_merge_cf(
2447 self.inner.inner(),
2448 writeopts.inner,
2449 cf.inner(),
2450 key.as_ptr() as *const c_char,
2451 key.len() as size_t,
2452 value.as_ptr() as *const c_char,
2453 value.len() as size_t,
2454 ));
2455 Ok(())
2456 }
2457 }
2458
2459 pub fn delete_opt<K: AsRef<[u8]>>(
2460 &self,
2461 key: K,
2462 writeopts: &WriteOptions,
2463 ) -> Result<(), Error> {
2464 let key = key.as_ref();
2465
2466 unsafe {
2467 ffi_try!(ffi::rocksdb_delete(
2468 self.inner.inner(),
2469 writeopts.inner,
2470 key.as_ptr() as *const c_char,
2471 key.len() as size_t,
2472 ));
2473 Ok(())
2474 }
2475 }
2476
2477 pub fn delete_cf_opt<K: AsRef<[u8]>>(
2478 &self,
2479 cf: &impl AsColumnFamilyRef,
2480 key: K,
2481 writeopts: &WriteOptions,
2482 ) -> Result<(), Error> {
2483 let key = key.as_ref();
2484
2485 unsafe {
2486 ffi_try!(ffi::rocksdb_delete_cf(
2487 self.inner.inner(),
2488 writeopts.inner,
2489 cf.inner(),
2490 key.as_ptr() as *const c_char,
2491 key.len() as size_t,
2492 ));
2493 Ok(())
2494 }
2495 }
2496
2497 pub fn delete_with_ts_opt<K, S>(
2501 &self,
2502 key: K,
2503 ts: S,
2504 writeopts: &WriteOptions,
2505 ) -> Result<(), Error>
2506 where
2507 K: AsRef<[u8]>,
2508 S: AsRef<[u8]>,
2509 {
2510 let key = key.as_ref();
2511 let ts = ts.as_ref();
2512 unsafe {
2513 ffi_try!(ffi::rocksdb_delete_with_ts(
2514 self.inner.inner(),
2515 writeopts.inner,
2516 key.as_ptr() as *const c_char,
2517 key.len() as size_t,
2518 ts.as_ptr() as *const c_char,
2519 ts.len() as size_t,
2520 ));
2521 Ok(())
2522 }
2523 }
2524
2525 pub fn delete_cf_with_ts_opt<K, S>(
2529 &self,
2530 cf: &impl AsColumnFamilyRef,
2531 key: K,
2532 ts: S,
2533 writeopts: &WriteOptions,
2534 ) -> Result<(), Error>
2535 where
2536 K: AsRef<[u8]>,
2537 S: AsRef<[u8]>,
2538 {
2539 let key = key.as_ref();
2540 let ts = ts.as_ref();
2541 unsafe {
2542 ffi_try!(ffi::rocksdb_delete_cf_with_ts(
2543 self.inner.inner(),
2544 writeopts.inner,
2545 cf.inner(),
2546 key.as_ptr() as *const c_char,
2547 key.len() as size_t,
2548 ts.as_ptr() as *const c_char,
2549 ts.len() as size_t,
2550 ));
2551 Ok(())
2552 }
2553 }
2554
2555 pub fn put<K, V>(&self, key: K, value: V) -> Result<(), Error>
2556 where
2557 K: AsRef<[u8]>,
2558 V: AsRef<[u8]>,
2559 {
2560 DEFAULT_WRITE_OPTS.with(|opts| self.put_opt(key, value, opts))
2561 }
2562
2563 pub fn put_cf<K, V>(&self, cf: &impl AsColumnFamilyRef, key: K, value: V) -> Result<(), Error>
2564 where
2565 K: AsRef<[u8]>,
2566 V: AsRef<[u8]>,
2567 {
2568 DEFAULT_WRITE_OPTS.with(|opts| self.put_cf_opt(cf, key, value, opts))
2569 }
2570
2571 pub fn put_with_ts<K, V, S>(&self, key: K, ts: S, value: V) -> Result<(), Error>
2578 where
2579 K: AsRef<[u8]>,
2580 V: AsRef<[u8]>,
2581 S: AsRef<[u8]>,
2582 {
2583 DEFAULT_WRITE_OPTS
2584 .with(|opts| self.put_with_ts_opt(key.as_ref(), ts.as_ref(), value.as_ref(), opts))
2585 }
2586
2587 pub fn put_cf_with_ts<K, V, S>(
2594 &self,
2595 cf: &impl AsColumnFamilyRef,
2596 key: K,
2597 ts: S,
2598 value: V,
2599 ) -> Result<(), Error>
2600 where
2601 K: AsRef<[u8]>,
2602 V: AsRef<[u8]>,
2603 S: AsRef<[u8]>,
2604 {
2605 DEFAULT_WRITE_OPTS.with(|opts| {
2606 self.put_cf_with_ts_opt(cf, key.as_ref(), ts.as_ref(), value.as_ref(), opts)
2607 })
2608 }
2609
2610 pub fn merge<K, V>(&self, key: K, value: V) -> Result<(), Error>
2611 where
2612 K: AsRef<[u8]>,
2613 V: AsRef<[u8]>,
2614 {
2615 DEFAULT_WRITE_OPTS.with(|opts| self.merge_opt(key, value, opts))
2616 }
2617
2618 pub fn merge_cf<K, V>(&self, cf: &impl AsColumnFamilyRef, key: K, value: V) -> Result<(), Error>
2619 where
2620 K: AsRef<[u8]>,
2621 V: AsRef<[u8]>,
2622 {
2623 DEFAULT_WRITE_OPTS.with(|opts| self.merge_cf_opt(cf, key, value, opts))
2624 }
2625
2626 pub fn delete<K: AsRef<[u8]>>(&self, key: K) -> Result<(), Error> {
2627 DEFAULT_WRITE_OPTS.with(|opts| self.delete_opt(key, opts))
2628 }
2629
2630 pub fn delete_cf<K: AsRef<[u8]>>(
2631 &self,
2632 cf: &impl AsColumnFamilyRef,
2633 key: K,
2634 ) -> Result<(), Error> {
2635 DEFAULT_WRITE_OPTS.with(|opts| self.delete_cf_opt(cf, key, opts))
2636 }
2637
2638 pub fn delete_with_ts<K: AsRef<[u8]>, S: AsRef<[u8]>>(
2642 &self,
2643 key: K,
2644 ts: S,
2645 ) -> Result<(), Error> {
2646 DEFAULT_WRITE_OPTS.with(|opts| self.delete_with_ts_opt(key, ts, opts))
2647 }
2648
2649 pub fn delete_cf_with_ts<K: AsRef<[u8]>, S: AsRef<[u8]>>(
2653 &self,
2654 cf: &impl AsColumnFamilyRef,
2655 key: K,
2656 ts: S,
2657 ) -> Result<(), Error> {
2658 DEFAULT_WRITE_OPTS.with(|opts| self.delete_cf_with_ts_opt(cf, key, ts, opts))
2659 }
2660
2661 pub fn single_delete_opt<K: AsRef<[u8]>>(
2681 &self,
2682 key: K,
2683 writeopts: &WriteOptions,
2684 ) -> Result<(), Error> {
2685 let key = key.as_ref();
2686
2687 unsafe {
2688 ffi_try!(ffi::rocksdb_singledelete(
2689 self.inner.inner(),
2690 writeopts.inner,
2691 key.as_ptr() as *const c_char,
2692 key.len() as size_t,
2693 ));
2694 Ok(())
2695 }
2696 }
2697
2698 pub fn single_delete_cf_opt<K: AsRef<[u8]>>(
2702 &self,
2703 cf: &impl AsColumnFamilyRef,
2704 key: K,
2705 writeopts: &WriteOptions,
2706 ) -> Result<(), Error> {
2707 let key = key.as_ref();
2708
2709 unsafe {
2710 ffi_try!(ffi::rocksdb_singledelete_cf(
2711 self.inner.inner(),
2712 writeopts.inner,
2713 cf.inner(),
2714 key.as_ptr() as *const c_char,
2715 key.len() as size_t,
2716 ));
2717 Ok(())
2718 }
2719 }
2720
2721 pub fn single_delete_with_ts_opt<K, S>(
2728 &self,
2729 key: K,
2730 ts: S,
2731 writeopts: &WriteOptions,
2732 ) -> Result<(), Error>
2733 where
2734 K: AsRef<[u8]>,
2735 S: AsRef<[u8]>,
2736 {
2737 let key = key.as_ref();
2738 let ts = ts.as_ref();
2739 unsafe {
2740 ffi_try!(ffi::rocksdb_singledelete_with_ts(
2741 self.inner.inner(),
2742 writeopts.inner,
2743 key.as_ptr() as *const c_char,
2744 key.len() as size_t,
2745 ts.as_ptr() as *const c_char,
2746 ts.len() as size_t,
2747 ));
2748 Ok(())
2749 }
2750 }
2751
2752 pub fn single_delete_cf_with_ts_opt<K, S>(
2759 &self,
2760 cf: &impl AsColumnFamilyRef,
2761 key: K,
2762 ts: S,
2763 writeopts: &WriteOptions,
2764 ) -> Result<(), Error>
2765 where
2766 K: AsRef<[u8]>,
2767 S: AsRef<[u8]>,
2768 {
2769 let key = key.as_ref();
2770 let ts = ts.as_ref();
2771 unsafe {
2772 ffi_try!(ffi::rocksdb_singledelete_cf_with_ts(
2773 self.inner.inner(),
2774 writeopts.inner,
2775 cf.inner(),
2776 key.as_ptr() as *const c_char,
2777 key.len() as size_t,
2778 ts.as_ptr() as *const c_char,
2779 ts.len() as size_t,
2780 ));
2781 Ok(())
2782 }
2783 }
2784
2785 pub fn single_delete<K: AsRef<[u8]>>(&self, key: K) -> Result<(), Error> {
2789 DEFAULT_WRITE_OPTS.with(|opts| self.single_delete_opt(key, opts))
2790 }
2791
2792 pub fn single_delete_cf<K: AsRef<[u8]>>(
2796 &self,
2797 cf: &impl AsColumnFamilyRef,
2798 key: K,
2799 ) -> Result<(), Error> {
2800 DEFAULT_WRITE_OPTS.with(|opts| self.single_delete_cf_opt(cf, key, opts))
2801 }
2802
2803 pub fn single_delete_with_ts<K: AsRef<[u8]>, S: AsRef<[u8]>>(
2810 &self,
2811 key: K,
2812 ts: S,
2813 ) -> Result<(), Error> {
2814 DEFAULT_WRITE_OPTS.with(|opts| self.single_delete_with_ts_opt(key, ts, opts))
2815 }
2816
2817 pub fn single_delete_cf_with_ts<K: AsRef<[u8]>, S: AsRef<[u8]>>(
2824 &self,
2825 cf: &impl AsColumnFamilyRef,
2826 key: K,
2827 ts: S,
2828 ) -> Result<(), Error> {
2829 DEFAULT_WRITE_OPTS.with(|opts| self.single_delete_cf_with_ts_opt(cf, key, ts, opts))
2830 }
2831
2832 pub fn compact_range<S: AsRef<[u8]>, E: AsRef<[u8]>>(&self, start: Option<S>, end: Option<E>) {
2834 unsafe {
2835 let start = start.as_ref().map(AsRef::as_ref);
2836 let end = end.as_ref().map(AsRef::as_ref);
2837
2838 ffi::rocksdb_compact_range(
2839 self.inner.inner(),
2840 opt_bytes_to_ptr(start),
2841 start.map_or(0, <[u8]>::len) as size_t,
2842 opt_bytes_to_ptr(end),
2843 end.map_or(0, <[u8]>::len) as size_t,
2844 );
2845 }
2846 }
2847
2848 pub fn compact_range_opt<S: AsRef<[u8]>, E: AsRef<[u8]>>(
2850 &self,
2851 start: Option<S>,
2852 end: Option<E>,
2853 opts: &CompactOptions,
2854 ) {
2855 unsafe {
2856 let start = start.as_ref().map(AsRef::as_ref);
2857 let end = end.as_ref().map(AsRef::as_ref);
2858
2859 ffi::rocksdb_compact_range_opt(
2860 self.inner.inner(),
2861 opts.inner,
2862 opt_bytes_to_ptr(start),
2863 start.map_or(0, <[u8]>::len) as size_t,
2864 opt_bytes_to_ptr(end),
2865 end.map_or(0, <[u8]>::len) as size_t,
2866 );
2867 }
2868 }
2869
2870 pub fn compact_range_cf<S: AsRef<[u8]>, E: AsRef<[u8]>>(
2873 &self,
2874 cf: &impl AsColumnFamilyRef,
2875 start: Option<S>,
2876 end: Option<E>,
2877 ) {
2878 unsafe {
2879 let start = start.as_ref().map(AsRef::as_ref);
2880 let end = end.as_ref().map(AsRef::as_ref);
2881
2882 ffi::rocksdb_compact_range_cf(
2883 self.inner.inner(),
2884 cf.inner(),
2885 opt_bytes_to_ptr(start),
2886 start.map_or(0, <[u8]>::len) as size_t,
2887 opt_bytes_to_ptr(end),
2888 end.map_or(0, <[u8]>::len) as size_t,
2889 );
2890 }
2891 }
2892
2893 pub fn compact_range_cf_opt<S: AsRef<[u8]>, E: AsRef<[u8]>>(
2895 &self,
2896 cf: &impl AsColumnFamilyRef,
2897 start: Option<S>,
2898 end: Option<E>,
2899 opts: &CompactOptions,
2900 ) {
2901 unsafe {
2902 let start = start.as_ref().map(AsRef::as_ref);
2903 let end = end.as_ref().map(AsRef::as_ref);
2904
2905 ffi::rocksdb_compact_range_cf_opt(
2906 self.inner.inner(),
2907 cf.inner(),
2908 opts.inner,
2909 opt_bytes_to_ptr(start),
2910 start.map_or(0, <[u8]>::len) as size_t,
2911 opt_bytes_to_ptr(end),
2912 end.map_or(0, <[u8]>::len) as size_t,
2913 );
2914 }
2915 }
2916
2917 pub fn wait_for_compact(&self, opts: &WaitForCompactOptions) -> Result<(), Error> {
2926 unsafe {
2927 ffi_try!(ffi::rocksdb_wait_for_compact(
2928 self.inner.inner(),
2929 opts.inner
2930 ));
2931 }
2932 Ok(())
2933 }
2934
2935 pub fn set_options(&self, opts: &[(&str, &str)]) -> Result<(), Error> {
2936 let copts = convert_options(opts)?;
2937 let cnames: Vec<*const c_char> = copts.iter().map(|opt| opt.0.as_ptr()).collect();
2938 let cvalues: Vec<*const c_char> = copts.iter().map(|opt| opt.1.as_ptr()).collect();
2939 let count = opts.len() as i32;
2940 unsafe {
2941 ffi_try!(ffi::rocksdb_set_options(
2942 self.inner.inner(),
2943 count,
2944 cnames.as_ptr(),
2945 cvalues.as_ptr(),
2946 ));
2947 }
2948 Ok(())
2949 }
2950
2951 pub fn set_options_cf(
2952 &self,
2953 cf: &impl AsColumnFamilyRef,
2954 opts: &[(&str, &str)],
2955 ) -> Result<(), Error> {
2956 let copts = convert_options(opts)?;
2957 let cnames: Vec<*const c_char> = copts.iter().map(|opt| opt.0.as_ptr()).collect();
2958 let cvalues: Vec<*const c_char> = copts.iter().map(|opt| opt.1.as_ptr()).collect();
2959 let count = opts.len() as i32;
2960 unsafe {
2961 ffi_try!(ffi::rocksdb_set_options_cf(
2962 self.inner.inner(),
2963 cf.inner(),
2964 count,
2965 cnames.as_ptr(),
2966 cvalues.as_ptr(),
2967 ));
2968 }
2969 Ok(())
2970 }
2971
2972 fn property_value_impl<R>(
2981 name: impl CStrLike,
2982 get_property: impl FnOnce(*const c_char) -> *mut c_char,
2983 parse: impl FnOnce(&str) -> Result<R, Error>,
2984 ) -> Result<Option<R>, Error> {
2985 let value = match name.bake() {
2986 Ok(prop_name) => get_property(prop_name.as_ptr()),
2987 Err(e) => {
2988 return Err(Error::new(format!(
2989 "Failed to convert property name to CString: {e}"
2990 )));
2991 }
2992 };
2993 if value.is_null() {
2994 return Ok(None);
2995 }
2996 let result = match unsafe { CStr::from_ptr(value) }.to_str() {
2997 Ok(s) => parse(s).map(|value| Some(value)),
2998 Err(e) => Err(Error::new(format!(
2999 "Failed to convert property value to string: {e}"
3000 ))),
3001 };
3002 unsafe {
3003 ffi::rocksdb_free(value as *mut c_void);
3004 }
3005 result
3006 }
3007
3008 pub fn property_value(&self, name: impl CStrLike) -> Result<Option<String>, Error> {
3013 Self::property_value_impl(
3014 name,
3015 |prop_name| unsafe { ffi::rocksdb_property_value(self.inner.inner(), prop_name) },
3016 |str_value| Ok(str_value.to_owned()),
3017 )
3018 }
3019
3020 pub fn property_value_cf(
3025 &self,
3026 cf: &impl AsColumnFamilyRef,
3027 name: impl CStrLike,
3028 ) -> Result<Option<String>, Error> {
3029 Self::property_value_impl(
3030 name,
3031 |prop_name| unsafe {
3032 ffi::rocksdb_property_value_cf(self.inner.inner(), cf.inner(), prop_name)
3033 },
3034 |str_value| Ok(str_value.to_owned()),
3035 )
3036 }
3037
3038 fn parse_property_int_value(value: &str) -> Result<u64, Error> {
3039 value.parse::<u64>().map_err(|err| {
3040 Error::new(format!(
3041 "Failed to convert property value {value} to int: {err}"
3042 ))
3043 })
3044 }
3045
3046 pub fn property_int_value(&self, name: impl CStrLike) -> Result<Option<u64>, Error> {
3051 Self::property_value_impl(
3052 name,
3053 |prop_name| unsafe { ffi::rocksdb_property_value(self.inner.inner(), prop_name) },
3054 Self::parse_property_int_value,
3055 )
3056 }
3057
3058 pub fn property_int_value_cf(
3063 &self,
3064 cf: &impl AsColumnFamilyRef,
3065 name: impl CStrLike,
3066 ) -> Result<Option<u64>, Error> {
3067 Self::property_value_impl(
3068 name,
3069 |prop_name| unsafe {
3070 ffi::rocksdb_property_value_cf(self.inner.inner(), cf.inner(), prop_name)
3071 },
3072 Self::parse_property_int_value,
3073 )
3074 }
3075
3076 pub fn latest_sequence_number(&self) -> u64 {
3078 unsafe { ffi::rocksdb_get_latest_sequence_number(self.inner.inner()) }
3079 }
3080
3081 pub fn get_approximate_sizes(&self, ranges: &[Range]) -> Vec<u64> {
3089 self.get_approximate_sizes_cfopt(None::<&ColumnFamily>, ranges)
3090 }
3091
3092 pub fn get_approximate_sizes_cf(
3093 &self,
3094 cf: &impl AsColumnFamilyRef,
3095 ranges: &[Range],
3096 ) -> Vec<u64> {
3097 self.get_approximate_sizes_cfopt(Some(cf), ranges)
3098 }
3099
3100 fn get_approximate_sizes_cfopt(
3101 &self,
3102 cf: Option<&impl AsColumnFamilyRef>,
3103 ranges: &[Range],
3104 ) -> Vec<u64> {
3105 let start_keys: Vec<*const c_char> = ranges
3106 .iter()
3107 .map(|x| x.start_key.as_ptr() as *const c_char)
3108 .collect();
3109 let start_key_lens: Vec<_> = ranges.iter().map(|x| x.start_key.len()).collect();
3110 let end_keys: Vec<*const c_char> = ranges
3111 .iter()
3112 .map(|x| x.end_key.as_ptr() as *const c_char)
3113 .collect();
3114 let end_key_lens: Vec<_> = ranges.iter().map(|x| x.end_key.len()).collect();
3115 let mut sizes: Vec<u64> = vec![0; ranges.len()];
3116 let (n, start_key_ptr, start_key_len_ptr, end_key_ptr, end_key_len_ptr, size_ptr) = (
3117 ranges.len() as i32,
3118 start_keys.as_ptr(),
3119 start_key_lens.as_ptr(),
3120 end_keys.as_ptr(),
3121 end_key_lens.as_ptr(),
3122 sizes.as_mut_ptr(),
3123 );
3124 let mut err: *mut c_char = ptr::null_mut();
3125 match cf {
3126 None => unsafe {
3127 ffi::rocksdb_approximate_sizes(
3128 self.inner.inner(),
3129 n,
3130 start_key_ptr,
3131 start_key_len_ptr,
3132 end_key_ptr,
3133 end_key_len_ptr,
3134 size_ptr,
3135 &raw mut err,
3136 );
3137 },
3138 Some(cf) => unsafe {
3139 ffi::rocksdb_approximate_sizes_cf(
3140 self.inner.inner(),
3141 cf.inner(),
3142 n,
3143 start_key_ptr,
3144 start_key_len_ptr,
3145 end_key_ptr,
3146 end_key_len_ptr,
3147 size_ptr,
3148 &raw mut err,
3149 );
3150 },
3151 }
3152 sizes
3153 }
3154
3155 pub fn get_updates_since(&self, seq_number: u64) -> Result<DBWALIterator, Error> {
3166 unsafe {
3167 let opts: *const ffi::rocksdb_wal_readoptions_t = ptr::null();
3171 let iter = ffi_try!(ffi::rocksdb_get_updates_since(
3172 self.inner.inner(),
3173 seq_number,
3174 opts
3175 ));
3176 Ok(DBWALIterator {
3177 inner: iter,
3178 start_seq_number: seq_number,
3179 })
3180 }
3181 }
3182
3183 pub fn try_catch_up_with_primary(&self) -> Result<(), Error> {
3186 unsafe {
3187 ffi_try!(ffi::rocksdb_try_catch_up_with_primary(self.inner.inner()));
3188 }
3189 Ok(())
3190 }
3191
3192 pub fn ingest_external_file<P: AsRef<Path>>(&self, paths: Vec<P>) -> Result<(), Error> {
3194 let opts = IngestExternalFileOptions::default();
3195 self.ingest_external_file_opts(&opts, paths)
3196 }
3197
3198 pub fn ingest_external_file_opts<P: AsRef<Path>>(
3200 &self,
3201 opts: &IngestExternalFileOptions,
3202 paths: Vec<P>,
3203 ) -> Result<(), Error> {
3204 let paths_v: Vec<CString> = paths.iter().map(to_cpath).collect::<Result<Vec<_>, _>>()?;
3205 let cpaths: Vec<_> = paths_v.iter().map(|path| path.as_ptr()).collect();
3206
3207 self.ingest_external_file_raw(opts, &paths_v, &cpaths)
3208 }
3209
3210 pub fn ingest_external_file_cf<P: AsRef<Path>>(
3213 &self,
3214 cf: &impl AsColumnFamilyRef,
3215 paths: Vec<P>,
3216 ) -> Result<(), Error> {
3217 let opts = IngestExternalFileOptions::default();
3218 self.ingest_external_file_cf_opts(cf, &opts, paths)
3219 }
3220
3221 pub fn ingest_external_file_cf_opts<P: AsRef<Path>>(
3223 &self,
3224 cf: &impl AsColumnFamilyRef,
3225 opts: &IngestExternalFileOptions,
3226 paths: Vec<P>,
3227 ) -> Result<(), Error> {
3228 let paths_v: Vec<CString> = paths.iter().map(to_cpath).collect::<Result<Vec<_>, _>>()?;
3229 let cpaths: Vec<_> = paths_v.iter().map(|path| path.as_ptr()).collect();
3230
3231 self.ingest_external_file_raw_cf(cf, opts, &paths_v, &cpaths)
3232 }
3233
3234 fn ingest_external_file_raw(
3235 &self,
3236 opts: &IngestExternalFileOptions,
3237 paths_v: &[CString],
3238 cpaths: &[*const c_char],
3239 ) -> Result<(), Error> {
3240 unsafe {
3241 ffi_try!(ffi::rocksdb_ingest_external_file(
3242 self.inner.inner(),
3243 cpaths.as_ptr(),
3244 paths_v.len(),
3245 opts.inner.cast_const()
3246 ));
3247 Ok(())
3248 }
3249 }
3250
3251 fn ingest_external_file_raw_cf(
3252 &self,
3253 cf: &impl AsColumnFamilyRef,
3254 opts: &IngestExternalFileOptions,
3255 paths_v: &[CString],
3256 cpaths: &[*const c_char],
3257 ) -> Result<(), Error> {
3258 unsafe {
3259 ffi_try!(ffi::rocksdb_ingest_external_file_cf(
3260 self.inner.inner(),
3261 cf.inner(),
3262 cpaths.as_ptr(),
3263 paths_v.len(),
3264 opts.inner.cast_const()
3265 ));
3266 Ok(())
3267 }
3268 }
3269
3270 pub fn get_column_family_metadata(&self) -> ColumnFamilyMetaData {
3272 unsafe {
3273 let ptr = ffi::rocksdb_get_column_family_metadata(self.inner.inner());
3274
3275 let metadata = ColumnFamilyMetaData {
3276 size: ffi::rocksdb_column_family_metadata_get_size(ptr),
3277 name: from_cstr_and_free(ffi::rocksdb_column_family_metadata_get_name(ptr)),
3278 file_count: ffi::rocksdb_column_family_metadata_get_file_count(ptr),
3279 };
3280
3281 ffi::rocksdb_column_family_metadata_destroy(ptr);
3283
3284 metadata
3286 }
3287 }
3288
3289 pub fn get_column_family_metadata_cf(
3291 &self,
3292 cf: &impl AsColumnFamilyRef,
3293 ) -> ColumnFamilyMetaData {
3294 unsafe {
3295 let ptr = ffi::rocksdb_get_column_family_metadata_cf(self.inner.inner(), cf.inner());
3296
3297 let metadata = ColumnFamilyMetaData {
3298 size: ffi::rocksdb_column_family_metadata_get_size(ptr),
3299 name: from_cstr_and_free(ffi::rocksdb_column_family_metadata_get_name(ptr)),
3300 file_count: ffi::rocksdb_column_family_metadata_get_file_count(ptr),
3301 };
3302
3303 ffi::rocksdb_column_family_metadata_destroy(ptr);
3305
3306 metadata
3308 }
3309 }
3310
3311 pub fn live_files(&self) -> Result<Vec<LiveFile>, Error> {
3314 unsafe {
3315 let livefiles_ptr = ffi::rocksdb_livefiles(self.inner.inner());
3316 if livefiles_ptr.is_null() {
3317 Err(Error::new("Could not get live files".to_owned()))
3318 } else {
3319 let files = LiveFile::from_rocksdb_livefiles_ptr(livefiles_ptr);
3320
3321 ffi::rocksdb_livefiles_destroy(livefiles_ptr);
3323
3324 Ok(files)
3326 }
3327 }
3328 }
3329
3330 pub fn delete_file_in_range<K: AsRef<[u8]>>(&self, from: K, to: K) -> Result<(), Error> {
3339 let from = from.as_ref();
3340 let to = to.as_ref();
3341 unsafe {
3342 ffi_try!(ffi::rocksdb_delete_file_in_range(
3343 self.inner.inner(),
3344 from.as_ptr() as *const c_char,
3345 from.len() as size_t,
3346 to.as_ptr() as *const c_char,
3347 to.len() as size_t,
3348 ));
3349 Ok(())
3350 }
3351 }
3352
3353 pub fn delete_file_in_range_cf<K: AsRef<[u8]>>(
3355 &self,
3356 cf: &impl AsColumnFamilyRef,
3357 from: K,
3358 to: K,
3359 ) -> Result<(), Error> {
3360 let from = from.as_ref();
3361 let to = to.as_ref();
3362 unsafe {
3363 ffi_try!(ffi::rocksdb_delete_file_in_range_cf(
3364 self.inner.inner(),
3365 cf.inner(),
3366 from.as_ptr() as *const c_char,
3367 from.len() as size_t,
3368 to.as_ptr() as *const c_char,
3369 to.len() as size_t,
3370 ));
3371 Ok(())
3372 }
3373 }
3374
3375 pub fn cancel_all_background_work(&self, wait: bool) {
3377 unsafe {
3378 ffi::rocksdb_cancel_all_background_work(self.inner.inner(), c_uchar::from(wait));
3379 }
3380 }
3381
3382 fn drop_column_family<C>(
3383 &self,
3384 cf_inner: *mut ffi::rocksdb_column_family_handle_t,
3385 cf: C,
3386 ) -> Result<(), Error> {
3387 unsafe {
3388 ffi_try!(ffi::rocksdb_drop_column_family(
3390 self.inner.inner(),
3391 cf_inner
3392 ));
3393 }
3394 drop(cf);
3397 Ok(())
3398 }
3399
3400 pub fn increase_full_history_ts_low<S: AsRef<[u8]>>(
3405 &self,
3406 cf: &impl AsColumnFamilyRef,
3407 ts: S,
3408 ) -> Result<(), Error> {
3409 let ts = ts.as_ref();
3410 unsafe {
3411 ffi_try!(ffi::rocksdb_increase_full_history_ts_low(
3412 self.inner.inner(),
3413 cf.inner(),
3414 ts.as_ptr() as *const c_char,
3415 ts.len() as size_t,
3416 ));
3417 Ok(())
3418 }
3419 }
3420
3421 pub fn get_full_history_ts_low(&self, cf: &impl AsColumnFamilyRef) -> Result<Vec<u8>, Error> {
3423 unsafe {
3424 let mut ts_lowlen = 0;
3425 let ts = ffi_try!(ffi::rocksdb_get_full_history_ts_low(
3426 self.inner.inner(),
3427 cf.inner(),
3428 &raw mut ts_lowlen,
3429 ));
3430
3431 if ts.is_null() {
3432 Err(Error::new("Could not get full_history_ts_low".to_owned()))
3433 } else {
3434 let mut vec = vec![0; ts_lowlen];
3435 ptr::copy_nonoverlapping(ts.cast::<u8>(), vec.as_mut_ptr(), ts_lowlen);
3436 ffi::rocksdb_free(ts as *mut c_void);
3437 Ok(vec)
3438 }
3439 }
3440 }
3441
3442 pub fn get_db_identity(&self) -> Result<Vec<u8>, Error> {
3444 unsafe {
3445 let mut length: usize = 0;
3446 let identity_ptr = ffi::rocksdb_get_db_identity(self.inner.inner(), &raw mut length);
3447 let identity_vec = raw_data(identity_ptr, length);
3448 ffi::rocksdb_free(identity_ptr as *mut c_void);
3449 identity_vec.ok_or_else(|| Error::new("get_db_identity returned NULL".to_string()))
3452 }
3453 }
3454}
3455
3456impl<I: DBInner> DBCommon<SingleThreaded, I> {
3457 pub fn create_cf<N: AsRef<str>>(&mut self, name: N, opts: &Options) -> Result<(), Error> {
3459 let inner = self.create_inner_cf_handle(name.as_ref(), opts)?;
3460 self.cfs
3461 .cfs
3462 .insert(name.as_ref().to_string(), ColumnFamily { inner });
3463 Ok(())
3464 }
3465
3466 #[doc = include_str!("db_create_column_family_with_import.md")]
3467 pub fn create_column_family_with_import<N: AsRef<str>>(
3468 &mut self,
3469 options: &Options,
3470 column_family_name: N,
3471 import_options: &ImportColumnFamilyOptions,
3472 metadata: &ExportImportFilesMetaData,
3473 ) -> Result<(), Error> {
3474 let name = column_family_name.as_ref();
3475 let c_name = CString::new(name).map_err(|err| {
3476 Error::new(format!(
3477 "Failed to convert name to CString while importing column family: {err}"
3478 ))
3479 })?;
3480 let inner = unsafe {
3481 ffi_try!(ffi::rocksdb_create_column_family_with_import(
3482 self.inner.inner(),
3483 options.inner,
3484 c_name.as_ptr(),
3485 import_options.inner,
3486 metadata.inner
3487 ))
3488 };
3489 self.cfs
3490 .cfs
3491 .insert(column_family_name.as_ref().into(), ColumnFamily { inner });
3492 Ok(())
3493 }
3494
3495 pub fn drop_cf(&mut self, name: &str) -> Result<(), Error> {
3497 match self.cfs.cfs.remove(name) {
3498 Some(cf) => self.drop_column_family(cf.inner, cf),
3499 _ => Err(Error::new(format!("Invalid column family: {name}"))),
3500 }
3501 }
3502
3503 pub fn cf_handle(&self, name: &str) -> Option<&ColumnFamily> {
3505 self.cfs.cfs.get(name)
3506 }
3507
3508 pub fn cf_names(&self) -> Vec<String> {
3512 self.cfs.cfs.keys().cloned().collect()
3513 }
3514}
3515
3516impl<I: DBInner> DBCommon<MultiThreaded, I> {
3517 pub fn create_cf<N: AsRef<str>>(&self, name: N, opts: &Options) -> Result<(), Error> {
3519 let mut cfs = self.cfs.cfs.write();
3522 let inner = self.create_inner_cf_handle(name.as_ref(), opts)?;
3523 cfs.insert(
3524 name.as_ref().to_string(),
3525 Arc::new(UnboundColumnFamily { inner }),
3526 );
3527 Ok(())
3528 }
3529
3530 #[doc = include_str!("db_create_column_family_with_import.md")]
3531 pub fn create_column_family_with_import<N: AsRef<str>>(
3532 &self,
3533 options: &Options,
3534 column_family_name: N,
3535 import_options: &ImportColumnFamilyOptions,
3536 metadata: &ExportImportFilesMetaData,
3537 ) -> Result<(), Error> {
3538 let mut cfs = self.cfs.cfs.write();
3540 let name = column_family_name.as_ref();
3541 let c_name = CString::new(name).map_err(|err| {
3542 Error::new(format!(
3543 "Failed to convert name to CString while importing column family: {err}"
3544 ))
3545 })?;
3546 let inner = unsafe {
3547 ffi_try!(ffi::rocksdb_create_column_family_with_import(
3548 self.inner.inner(),
3549 options.inner,
3550 c_name.as_ptr(),
3551 import_options.inner,
3552 metadata.inner
3553 ))
3554 };
3555 cfs.insert(
3556 column_family_name.as_ref().to_string(),
3557 Arc::new(UnboundColumnFamily { inner }),
3558 );
3559 Ok(())
3560 }
3561
3562 pub fn drop_cf(&self, name: &str) -> Result<(), Error> {
3565 match self.cfs.cfs.write().remove(name) {
3566 Some(cf) => self.drop_column_family(cf.inner, cf),
3567 _ => Err(Error::new(format!("Invalid column family: {name}"))),
3568 }
3569 }
3570
3571 pub fn cf_handle(&'_ self, name: &str) -> Option<Arc<BoundColumnFamily<'_>>> {
3573 self.cfs
3574 .cfs
3575 .read()
3576 .get(name)
3577 .cloned()
3578 .map(UnboundColumnFamily::bound_column_family)
3579 }
3580
3581 pub fn cf_names(&self) -> Vec<String> {
3585 self.cfs.cfs.read().keys().cloned().collect()
3586 }
3587}
3588
3589impl<T: ThreadMode, I: DBInner> Drop for DBCommon<T, I> {
3590 fn drop(&mut self) {
3591 self.cfs.drop_all_cfs_internal();
3592 }
3593}
3594
3595impl<T: ThreadMode, I: DBInner> fmt::Debug for DBCommon<T, I> {
3596 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3597 write!(f, "RocksDB {{ path: {} }}", self.path().display())
3598 }
3599}
3600
3601#[derive(Debug, Clone)]
3603pub struct ColumnFamilyMetaData {
3604 pub size: u64,
3607 pub name: String,
3609 pub file_count: usize,
3611}
3612
3613#[derive(Debug, Clone)]
3615pub struct LiveFile {
3616 pub column_family_name: String,
3618 pub name: String,
3620 pub directory: String,
3623 pub size: usize,
3625 pub level: i32,
3627 pub start_key: Option<Vec<u8>>,
3629 pub end_key: Option<Vec<u8>>,
3631 pub smallest_seqno: u64,
3632 pub largest_seqno: u64,
3633 pub num_entries: u64,
3635 pub num_deletions: u64,
3637}
3638
3639impl LiveFile {
3640 pub(crate) fn from_rocksdb_livefiles_ptr(
3642 files: *const ffi::rocksdb_livefiles_t,
3643 ) -> Vec<LiveFile> {
3644 unsafe {
3645 let n = ffi::rocksdb_livefiles_count(files);
3646
3647 let mut livefiles = Vec::with_capacity(n as usize);
3648 let mut key_size: usize = 0;
3649
3650 for i in 0..n {
3651 let column_family_name =
3653 from_cstr_without_free(ffi::rocksdb_livefiles_column_family_name(files, i));
3654 let name = from_cstr_without_free(ffi::rocksdb_livefiles_name(files, i));
3655 let directory = from_cstr_without_free(ffi::rocksdb_livefiles_directory(files, i));
3656 let size = ffi::rocksdb_livefiles_size(files, i);
3657 let level = ffi::rocksdb_livefiles_level(files, i);
3658
3659 let smallest_key = ffi::rocksdb_livefiles_smallestkey(files, i, &raw mut key_size);
3661 let smallest_key = raw_data(smallest_key, key_size);
3662
3663 let largest_key = ffi::rocksdb_livefiles_largestkey(files, i, &raw mut key_size);
3665 let largest_key = raw_data(largest_key, key_size);
3666
3667 livefiles.push(LiveFile {
3668 column_family_name,
3669 name,
3670 directory,
3671 size,
3672 level,
3673 start_key: smallest_key,
3674 end_key: largest_key,
3675 largest_seqno: ffi::rocksdb_livefiles_largest_seqno(files, i),
3676 smallest_seqno: ffi::rocksdb_livefiles_smallest_seqno(files, i),
3677 num_entries: ffi::rocksdb_livefiles_entries(files, i),
3678 num_deletions: ffi::rocksdb_livefiles_deletions(files, i),
3679 });
3680 }
3681
3682 livefiles
3683 }
3684 }
3685}
3686
3687struct LiveFileGuard(*mut rocksdb_livefile_t);
3688
3689impl LiveFileGuard {
3690 fn into_raw(mut self) -> *mut rocksdb_livefile_t {
3691 let ptr = self.0;
3692 self.0 = ptr::null_mut();
3693 ptr
3694 }
3695}
3696
3697impl Drop for LiveFileGuard {
3698 fn drop(&mut self) {
3699 if !self.0.is_null() {
3700 unsafe {
3701 rocksdb_livefile_destroy(self.0);
3702 }
3703 }
3704 }
3705}
3706
3707struct LiveFilesGuard(*mut rocksdb_livefiles_t);
3708
3709impl LiveFilesGuard {
3710 fn into_raw(mut self) -> *mut rocksdb_livefiles_t {
3711 let ptr = self.0;
3712 self.0 = ptr::null_mut();
3713 ptr
3714 }
3715}
3716
3717impl Drop for LiveFilesGuard {
3718 fn drop(&mut self) {
3719 if !self.0.is_null() {
3720 unsafe {
3721 rocksdb_livefiles_destroy(self.0);
3722 }
3723 }
3724 }
3725}
3726
3727#[derive(Debug)]
3732pub struct ExportImportFilesMetaData {
3733 pub(crate) inner: *mut ffi::rocksdb_export_import_files_metadata_t,
3734}
3735
3736impl ExportImportFilesMetaData {
3737 pub fn get_db_comparator_name(&self) -> String {
3738 unsafe {
3739 let c_name =
3740 ffi::rocksdb_export_import_files_metadata_get_db_comparator_name(self.inner);
3741 from_cstr_and_free(c_name)
3742 }
3743 }
3744
3745 pub fn set_db_comparator_name(&mut self, name: &str) {
3746 let c_name = CString::new(name.as_bytes()).unwrap();
3747 unsafe {
3748 ffi::rocksdb_export_import_files_metadata_set_db_comparator_name(
3749 self.inner,
3750 c_name.as_ptr(),
3751 );
3752 };
3753 }
3754
3755 pub fn get_files(&self) -> Vec<LiveFile> {
3756 unsafe {
3757 let livefiles_ptr = ffi::rocksdb_export_import_files_metadata_get_files(self.inner);
3758 let files = LiveFile::from_rocksdb_livefiles_ptr(livefiles_ptr);
3759 ffi::rocksdb_livefiles_destroy(livefiles_ptr);
3760 files
3761 }
3762 }
3763
3764 pub fn set_files(&mut self, files: &[LiveFile]) -> Result<(), Error> {
3765 static EMPTY: [u8; 0] = [];
3767 let empty_ptr = EMPTY.as_ptr() as *const libc::c_char;
3768
3769 unsafe {
3770 let live_files = LiveFilesGuard(ffi::rocksdb_livefiles_create());
3771
3772 for file in files {
3773 let live_file = LiveFileGuard(ffi::rocksdb_livefile_create());
3774 ffi::rocksdb_livefile_set_level(live_file.0, file.level);
3775
3776 let c_cf_name = CString::new(file.column_family_name.as_str()).map_err(|err| {
3778 Error::new(format!("Unable to convert column family to CString: {err}"))
3779 })?;
3780 ffi::rocksdb_livefile_set_column_family_name(live_file.0, c_cf_name.as_ptr());
3781
3782 let c_name = CString::new(file.name.as_str()).map_err(|err| {
3783 Error::new(format!("Unable to convert file name to CString: {err}"))
3784 })?;
3785 ffi::rocksdb_livefile_set_name(live_file.0, c_name.as_ptr());
3786
3787 let c_directory = CString::new(file.directory.as_str()).map_err(|err| {
3788 Error::new(format!("Unable to convert directory to CString: {err}"))
3789 })?;
3790 ffi::rocksdb_livefile_set_directory(live_file.0, c_directory.as_ptr());
3791
3792 ffi::rocksdb_livefile_set_size(live_file.0, file.size);
3793
3794 let (start_key_ptr, start_key_len) = match &file.start_key {
3795 None => (empty_ptr, 0),
3796 Some(key) => (key.as_ptr() as *const libc::c_char, key.len()),
3797 };
3798 ffi::rocksdb_livefile_set_smallest_key(live_file.0, start_key_ptr, start_key_len);
3799
3800 let (largest_key_ptr, largest_key_len) = match &file.end_key {
3801 None => (empty_ptr, 0),
3802 Some(key) => (key.as_ptr() as *const libc::c_char, key.len()),
3803 };
3804 ffi::rocksdb_livefile_set_largest_key(
3805 live_file.0,
3806 largest_key_ptr,
3807 largest_key_len,
3808 );
3809 ffi::rocksdb_livefile_set_smallest_seqno(live_file.0, file.smallest_seqno);
3810 ffi::rocksdb_livefile_set_largest_seqno(live_file.0, file.largest_seqno);
3811 ffi::rocksdb_livefile_set_num_entries(live_file.0, file.num_entries);
3812 ffi::rocksdb_livefile_set_num_deletions(live_file.0, file.num_deletions);
3813
3814 ffi::rocksdb_livefiles_add(live_files.0, live_file.into_raw());
3816 }
3817
3818 ffi::rocksdb_export_import_files_metadata_set_files(self.inner, live_files.into_raw());
3820 Ok(())
3821 }
3822 }
3823}
3824
3825impl Default for ExportImportFilesMetaData {
3826 fn default() -> Self {
3827 let inner = unsafe { ffi::rocksdb_export_import_files_metadata_create() };
3828 assert!(
3829 !inner.is_null(),
3830 "Could not create rocksdb_export_import_files_metadata_t"
3831 );
3832
3833 Self { inner }
3834 }
3835}
3836
3837impl Drop for ExportImportFilesMetaData {
3838 fn drop(&mut self) {
3839 unsafe {
3840 ffi::rocksdb_export_import_files_metadata_destroy(self.inner);
3841 }
3842 }
3843}
3844
3845unsafe impl Send for ExportImportFilesMetaData {}
3846unsafe impl Sync for ExportImportFilesMetaData {}
3847
3848fn convert_options(opts: &[(&str, &str)]) -> Result<Vec<(CString, CString)>, Error> {
3849 opts.iter()
3850 .map(|(name, value)| {
3851 let cname = match CString::new(name.as_bytes()) {
3852 Ok(cname) => cname,
3853 Err(e) => return Err(Error::new(format!("Invalid option name `{e}`"))),
3854 };
3855 let cvalue = match CString::new(value.as_bytes()) {
3856 Ok(cvalue) => cvalue,
3857 Err(e) => return Err(Error::new(format!("Invalid option value: `{e}`"))),
3858 };
3859 Ok((cname, cvalue))
3860 })
3861 .collect()
3862}
3863
3864pub(crate) fn convert_values(
3865 values: Vec<*mut c_char>,
3866 values_sizes: Vec<usize>,
3867 errors: Vec<*mut c_char>,
3868) -> Vec<Result<Option<Vec<u8>>, Error>> {
3869 values
3870 .into_iter()
3871 .zip(values_sizes)
3872 .zip(errors)
3873 .map(|((v, s), e)| {
3874 if e.is_null() {
3875 let value = unsafe { crate::ffi_util::raw_data(v, s) };
3876 unsafe {
3877 ffi::rocksdb_free(v as *mut c_void);
3878 }
3879 Ok(value)
3880 } else {
3881 Err(convert_rocksdb_error(e))
3882 }
3883 })
3884 .collect()
3885}