1use crate::{
17 column_family::{AsColumnFamilyRef, BoundColumnFamily, UnboundColumnFamily},
18 db_options::OptionsMustOutliveDB,
19 ffi,
20 ffi_util::{
21 convert_rocksdb_error, from_cstr_and_free, from_cstr_without_free, opt_bytes_to_ptr,
22 raw_data, to_cpath, CStrLike,
23 },
24 ColumnFamily, ColumnFamilyDescriptor, CompactOptions, DBIteratorWithThreadMode,
25 DBPinnableSlice, DBRawIteratorWithThreadMode, DBWALIterator, Direction, Error, FlushOptions,
26 IngestExternalFileOptions, IteratorMode, Options, ReadOptions, SnapshotWithThreadMode,
27 WaitForCompactOptions, WriteBatch, WriteOptions, DEFAULT_COLUMN_FAMILY_NAME,
28};
29
30use crate::column_family::ColumnFamilyTtl;
31use crate::ffi_util::CSlice;
32use libc::{self, c_char, c_int, c_uchar, c_void, size_t};
33use std::collections::BTreeMap;
34use std::ffi::{CStr, CString};
35use std::fmt;
36use std::fs;
37use std::iter;
38use std::path::Path;
39use std::path::PathBuf;
40use std::ptr;
41use std::slice;
42use std::str;
43use std::sync::Arc;
44use std::sync::RwLock;
45use std::time::Duration;
46
47pub struct Range<'a> {
51 start_key: &'a [u8],
52 end_key: &'a [u8],
53}
54
55impl<'a> Range<'a> {
56 pub fn new(start_key: &'a [u8], end_key: &'a [u8]) -> Range<'a> {
57 Range { start_key, end_key }
58 }
59}
60
61pub trait ThreadMode {
72 fn new_cf_map_internal(
74 cf_map: BTreeMap<String, *mut ffi::rocksdb_column_family_handle_t>,
75 ) -> Self;
76 fn drop_all_cfs_internal(&mut self);
78}
79
80pub struct SingleThreaded {
87 pub(crate) cfs: BTreeMap<String, ColumnFamily>,
88}
89
90pub struct MultiThreaded {
96 pub(crate) cfs: RwLock<BTreeMap<String, Arc<UnboundColumnFamily>>>,
97}
98
99impl ThreadMode for SingleThreaded {
100 fn new_cf_map_internal(
101 cfs: BTreeMap<String, *mut ffi::rocksdb_column_family_handle_t>,
102 ) -> Self {
103 Self {
104 cfs: cfs
105 .into_iter()
106 .map(|(n, c)| (n, ColumnFamily { inner: c }))
107 .collect(),
108 }
109 }
110
111 fn drop_all_cfs_internal(&mut self) {
112 self.cfs.clear();
114 }
115}
116
117impl ThreadMode for MultiThreaded {
118 fn new_cf_map_internal(
119 cfs: BTreeMap<String, *mut ffi::rocksdb_column_family_handle_t>,
120 ) -> Self {
121 Self {
122 cfs: RwLock::new(
123 cfs.into_iter()
124 .map(|(n, c)| (n, Arc::new(UnboundColumnFamily { inner: c })))
125 .collect(),
126 ),
127 }
128 }
129
130 fn drop_all_cfs_internal(&mut self) {
131 self.cfs.write().unwrap().clear();
133 }
134}
135
136pub trait DBInner {
138 fn inner(&self) -> *mut ffi::rocksdb_t;
139}
140
141pub struct DBCommon<T: ThreadMode, D: DBInner> {
146 pub(crate) inner: D,
147 cfs: T, path: PathBuf,
149 _outlive: Vec<OptionsMustOutliveDB>,
150}
151
152pub trait DBAccess {
155 unsafe fn create_snapshot(&self) -> *const ffi::rocksdb_snapshot_t;
156
157 unsafe fn release_snapshot(&self, snapshot: *const ffi::rocksdb_snapshot_t);
158
159 unsafe fn create_iterator(&self, readopts: &ReadOptions) -> *mut ffi::rocksdb_iterator_t;
160
161 unsafe fn create_iterator_cf(
162 &self,
163 cf_handle: *mut ffi::rocksdb_column_family_handle_t,
164 readopts: &ReadOptions,
165 ) -> *mut ffi::rocksdb_iterator_t;
166
167 fn get_opt<K: AsRef<[u8]>>(
168 &self,
169 key: K,
170 readopts: &ReadOptions,
171 ) -> Result<Option<Vec<u8>>, Error>;
172
173 fn get_cf_opt<K: AsRef<[u8]>>(
174 &self,
175 cf: &impl AsColumnFamilyRef,
176 key: K,
177 readopts: &ReadOptions,
178 ) -> Result<Option<Vec<u8>>, Error>;
179
180 fn get_pinned_opt<K: AsRef<[u8]>>(
181 &self,
182 key: K,
183 readopts: &ReadOptions,
184 ) -> Result<Option<DBPinnableSlice>, Error>;
185
186 fn get_pinned_cf_opt<K: AsRef<[u8]>>(
187 &self,
188 cf: &impl AsColumnFamilyRef,
189 key: K,
190 readopts: &ReadOptions,
191 ) -> Result<Option<DBPinnableSlice>, Error>;
192
193 fn multi_get_opt<K, I>(
194 &self,
195 keys: I,
196 readopts: &ReadOptions,
197 ) -> Vec<Result<Option<Vec<u8>>, Error>>
198 where
199 K: AsRef<[u8]>,
200 I: IntoIterator<Item = K>;
201
202 fn multi_get_cf_opt<'b, K, I, W>(
203 &self,
204 keys_cf: I,
205 readopts: &ReadOptions,
206 ) -> Vec<Result<Option<Vec<u8>>, Error>>
207 where
208 K: AsRef<[u8]>,
209 I: IntoIterator<Item = (&'b W, K)>,
210 W: AsColumnFamilyRef + 'b;
211}
212
213impl<T: ThreadMode, D: DBInner> DBAccess for DBCommon<T, D> {
214 unsafe fn create_snapshot(&self) -> *const ffi::rocksdb_snapshot_t {
215 unsafe { ffi::rocksdb_create_snapshot(self.inner.inner()) }
216 }
217
218 unsafe fn release_snapshot(&self, snapshot: *const ffi::rocksdb_snapshot_t) {
219 unsafe { ffi::rocksdb_release_snapshot(self.inner.inner(), snapshot) };
220 }
221
222 unsafe fn create_iterator(&self, readopts: &ReadOptions) -> *mut ffi::rocksdb_iterator_t {
223 unsafe { ffi::rocksdb_create_iterator(self.inner.inner(), readopts.inner) }
224 }
225
226 unsafe fn create_iterator_cf(
227 &self,
228 cf_handle: *mut ffi::rocksdb_column_family_handle_t,
229 readopts: &ReadOptions,
230 ) -> *mut ffi::rocksdb_iterator_t {
231 unsafe { ffi::rocksdb_create_iterator_cf(self.inner.inner(), readopts.inner, cf_handle) }
232 }
233
234 fn get_opt<K: AsRef<[u8]>>(
235 &self,
236 key: K,
237 readopts: &ReadOptions,
238 ) -> Result<Option<Vec<u8>>, Error> {
239 self.get_opt(key, readopts)
240 }
241
242 fn get_cf_opt<K: AsRef<[u8]>>(
243 &self,
244 cf: &impl AsColumnFamilyRef,
245 key: K,
246 readopts: &ReadOptions,
247 ) -> Result<Option<Vec<u8>>, Error> {
248 self.get_cf_opt(cf, key, readopts)
249 }
250
251 fn get_pinned_opt<K: AsRef<[u8]>>(
252 &self,
253 key: K,
254 readopts: &ReadOptions,
255 ) -> Result<Option<DBPinnableSlice>, Error> {
256 self.get_pinned_opt(key, readopts)
257 }
258
259 fn get_pinned_cf_opt<K: AsRef<[u8]>>(
260 &self,
261 cf: &impl AsColumnFamilyRef,
262 key: K,
263 readopts: &ReadOptions,
264 ) -> Result<Option<DBPinnableSlice>, Error> {
265 self.get_pinned_cf_opt(cf, key, readopts)
266 }
267
268 fn multi_get_opt<K, Iter>(
269 &self,
270 keys: Iter,
271 readopts: &ReadOptions,
272 ) -> Vec<Result<Option<Vec<u8>>, Error>>
273 where
274 K: AsRef<[u8]>,
275 Iter: IntoIterator<Item = K>,
276 {
277 self.multi_get_opt(keys, readopts)
278 }
279
280 fn multi_get_cf_opt<'b, K, Iter, W>(
281 &self,
282 keys_cf: Iter,
283 readopts: &ReadOptions,
284 ) -> Vec<Result<Option<Vec<u8>>, Error>>
285 where
286 K: AsRef<[u8]>,
287 Iter: IntoIterator<Item = (&'b W, K)>,
288 W: AsColumnFamilyRef + 'b,
289 {
290 self.multi_get_cf_opt(keys_cf, readopts)
291 }
292}
293
294pub struct DBWithThreadModeInner {
295 inner: *mut ffi::rocksdb_t,
296}
297
298impl DBInner for DBWithThreadModeInner {
299 fn inner(&self) -> *mut ffi::rocksdb_t {
300 self.inner
301 }
302}
303
304impl Drop for DBWithThreadModeInner {
305 fn drop(&mut self) {
306 unsafe {
307 ffi::rocksdb_close(self.inner);
308 }
309 }
310}
311
312pub type DBWithThreadMode<T> = DBCommon<T, DBWithThreadModeInner>;
317
318#[cfg(not(feature = "multi-threaded-cf"))]
341pub type DB = DBWithThreadMode<SingleThreaded>;
342
343#[cfg(feature = "multi-threaded-cf")]
344pub type DB = DBWithThreadMode<MultiThreaded>;
345
346unsafe impl<T: ThreadMode + Send, I: DBInner> Send for DBCommon<T, I> {}
350
351unsafe impl<T: ThreadMode, I: DBInner> Sync for DBCommon<T, I> {}
354
355enum AccessType<'a> {
357 ReadWrite,
358 ReadOnly { error_if_log_file_exist: bool },
359 Secondary { secondary_path: &'a Path },
360 WithTTL { ttl: Duration },
361}
362
363impl<T: ThreadMode> DBWithThreadMode<T> {
365 pub fn open_default<P: AsRef<Path>>(path: P) -> Result<Self, Error> {
367 let mut opts = Options::default();
368 opts.create_if_missing(true);
369 Self::open(&opts, path)
370 }
371
372 pub fn open<P: AsRef<Path>>(opts: &Options, path: P) -> Result<Self, Error> {
374 Self::open_cf(opts, path, None::<&str>)
375 }
376
377 pub fn open_for_read_only<P: AsRef<Path>>(
379 opts: &Options,
380 path: P,
381 error_if_log_file_exist: bool,
382 ) -> Result<Self, Error> {
383 Self::open_cf_for_read_only(opts, path, None::<&str>, error_if_log_file_exist)
384 }
385
386 pub fn open_as_secondary<P: AsRef<Path>>(
388 opts: &Options,
389 primary_path: P,
390 secondary_path: P,
391 ) -> Result<Self, Error> {
392 Self::open_cf_as_secondary(opts, primary_path, secondary_path, None::<&str>)
393 }
394
395 pub fn open_with_ttl<P: AsRef<Path>>(
400 opts: &Options,
401 path: P,
402 ttl: Duration,
403 ) -> Result<Self, Error> {
404 Self::open_cf_descriptors_with_ttl(opts, path, std::iter::empty(), ttl)
405 }
406
407 pub fn open_cf_with_ttl<P, I, N>(
411 opts: &Options,
412 path: P,
413 cfs: I,
414 ttl: Duration,
415 ) -> Result<Self, Error>
416 where
417 P: AsRef<Path>,
418 I: IntoIterator<Item = N>,
419 N: AsRef<str>,
420 {
421 let cfs = cfs
422 .into_iter()
423 .map(|name| ColumnFamilyDescriptor::new(name.as_ref(), Options::default()));
424
425 Self::open_cf_descriptors_with_ttl(opts, path, cfs, ttl)
426 }
427
428 pub fn open_cf_descriptors_with_ttl<P, I>(
442 opts: &Options,
443 path: P,
444 cfs: I,
445 ttl: Duration,
446 ) -> Result<Self, Error>
447 where
448 P: AsRef<Path>,
449 I: IntoIterator<Item = ColumnFamilyDescriptor>,
450 {
451 Self::open_cf_descriptors_internal(opts, path, cfs, &AccessType::WithTTL { ttl })
452 }
453
454 pub fn open_cf<P, I, N>(opts: &Options, path: P, cfs: I) -> Result<Self, Error>
458 where
459 P: AsRef<Path>,
460 I: IntoIterator<Item = N>,
461 N: AsRef<str>,
462 {
463 let cfs = cfs
464 .into_iter()
465 .map(|name| ColumnFamilyDescriptor::new(name.as_ref(), Options::default()));
466
467 Self::open_cf_descriptors_internal(opts, path, cfs, &AccessType::ReadWrite)
468 }
469
470 pub fn open_cf_with_opts<P, I, N>(opts: &Options, path: P, cfs: I) -> Result<Self, Error>
474 where
475 P: AsRef<Path>,
476 I: IntoIterator<Item = (N, Options)>,
477 N: AsRef<str>,
478 {
479 let cfs = cfs
480 .into_iter()
481 .map(|(name, opts)| ColumnFamilyDescriptor::new(name.as_ref(), opts));
482
483 Self::open_cf_descriptors(opts, path, cfs)
484 }
485
486 pub fn open_cf_for_read_only<P, I, N>(
490 opts: &Options,
491 path: P,
492 cfs: I,
493 error_if_log_file_exist: bool,
494 ) -> Result<Self, Error>
495 where
496 P: AsRef<Path>,
497 I: IntoIterator<Item = N>,
498 N: AsRef<str>,
499 {
500 let cfs = cfs
501 .into_iter()
502 .map(|name| ColumnFamilyDescriptor::new(name.as_ref(), Options::default()));
503
504 Self::open_cf_descriptors_internal(
505 opts,
506 path,
507 cfs,
508 &AccessType::ReadOnly {
509 error_if_log_file_exist,
510 },
511 )
512 }
513
514 pub fn open_cf_with_opts_for_read_only<P, I, N>(
518 db_opts: &Options,
519 path: P,
520 cfs: I,
521 error_if_log_file_exist: bool,
522 ) -> Result<Self, Error>
523 where
524 P: AsRef<Path>,
525 I: IntoIterator<Item = (N, Options)>,
526 N: AsRef<str>,
527 {
528 let cfs = cfs
529 .into_iter()
530 .map(|(name, cf_opts)| ColumnFamilyDescriptor::new(name.as_ref(), cf_opts));
531
532 Self::open_cf_descriptors_internal(
533 db_opts,
534 path,
535 cfs,
536 &AccessType::ReadOnly {
537 error_if_log_file_exist,
538 },
539 )
540 }
541
542 pub fn open_cf_descriptors_read_only<P, I>(
547 opts: &Options,
548 path: P,
549 cfs: I,
550 error_if_log_file_exist: bool,
551 ) -> Result<Self, Error>
552 where
553 P: AsRef<Path>,
554 I: IntoIterator<Item = ColumnFamilyDescriptor>,
555 {
556 Self::open_cf_descriptors_internal(
557 opts,
558 path,
559 cfs,
560 &AccessType::ReadOnly {
561 error_if_log_file_exist,
562 },
563 )
564 }
565
566 pub fn open_cf_as_secondary<P, I, N>(
570 opts: &Options,
571 primary_path: P,
572 secondary_path: P,
573 cfs: I,
574 ) -> Result<Self, Error>
575 where
576 P: AsRef<Path>,
577 I: IntoIterator<Item = N>,
578 N: AsRef<str>,
579 {
580 let cfs = cfs
581 .into_iter()
582 .map(|name| ColumnFamilyDescriptor::new(name.as_ref(), Options::default()));
583
584 Self::open_cf_descriptors_internal(
585 opts,
586 primary_path,
587 cfs,
588 &AccessType::Secondary {
589 secondary_path: secondary_path.as_ref(),
590 },
591 )
592 }
593
594 pub fn open_cf_descriptors_as_secondary<P, I>(
599 opts: &Options,
600 path: P,
601 secondary_path: P,
602 cfs: I,
603 ) -> Result<Self, Error>
604 where
605 P: AsRef<Path>,
606 I: IntoIterator<Item = ColumnFamilyDescriptor>,
607 {
608 Self::open_cf_descriptors_internal(
609 opts,
610 path,
611 cfs,
612 &AccessType::Secondary {
613 secondary_path: secondary_path.as_ref(),
614 },
615 )
616 }
617
618 pub fn open_cf_descriptors<P, I>(opts: &Options, path: P, cfs: I) -> Result<Self, Error>
622 where
623 P: AsRef<Path>,
624 I: IntoIterator<Item = ColumnFamilyDescriptor>,
625 {
626 Self::open_cf_descriptors_internal(opts, path, cfs, &AccessType::ReadWrite)
627 }
628
629 fn open_cf_descriptors_internal<P, I>(
631 opts: &Options,
632 path: P,
633 cfs: I,
634 access_type: &AccessType,
635 ) -> Result<Self, Error>
636 where
637 P: AsRef<Path>,
638 I: IntoIterator<Item = ColumnFamilyDescriptor>,
639 {
640 let cfs: Vec<_> = cfs.into_iter().collect();
641 let outlive = iter::once(opts.outlive.clone())
642 .chain(cfs.iter().map(|cf| cf.options.outlive.clone()))
643 .collect();
644
645 let cpath = to_cpath(&path)?;
646
647 if let Err(e) = fs::create_dir_all(&path) {
648 return Err(Error::new(format!(
649 "Failed to create RocksDB directory: `{e:?}`."
650 )));
651 }
652
653 let db: *mut ffi::rocksdb_t;
654 let mut cf_map = BTreeMap::new();
655
656 if cfs.is_empty() {
657 db = Self::open_raw(opts, &cpath, access_type)?;
658 } else {
659 let mut cfs_v = cfs;
660 if !cfs_v.iter().any(|cf| cf.name == DEFAULT_COLUMN_FAMILY_NAME) {
662 cfs_v.push(ColumnFamilyDescriptor {
663 name: String::from(DEFAULT_COLUMN_FAMILY_NAME),
664 options: Options::default(),
665 ttl: ColumnFamilyTtl::SameAsDb,
666 });
667 }
668 let c_cfs: Vec<CString> = cfs_v
671 .iter()
672 .map(|cf| CString::new(cf.name.as_bytes()).unwrap())
673 .collect();
674
675 let cfnames: Vec<_> = c_cfs.iter().map(|cf| cf.as_ptr()).collect();
676
677 let mut cfhandles: Vec<_> = cfs_v.iter().map(|_| ptr::null_mut()).collect();
679
680 let cfopts: Vec<_> = cfs_v
681 .iter()
682 .map(|cf| cf.options.inner.cast_const())
683 .collect();
684
685 db = Self::open_cf_raw(
686 opts,
687 &cpath,
688 &cfs_v,
689 &cfnames,
690 &cfopts,
691 &mut cfhandles,
692 access_type,
693 )?;
694 for handle in &cfhandles {
695 if handle.is_null() {
696 return Err(Error::new(
697 "Received null column family handle from DB.".to_owned(),
698 ));
699 }
700 }
701
702 for (cf_desc, inner) in cfs_v.iter().zip(cfhandles) {
703 cf_map.insert(cf_desc.name.clone(), inner);
704 }
705 }
706
707 if db.is_null() {
708 return Err(Error::new("Could not initialize database.".to_owned()));
709 }
710
711 Ok(Self {
712 inner: DBWithThreadModeInner { inner: db },
713 path: path.as_ref().to_path_buf(),
714 cfs: T::new_cf_map_internal(cf_map),
715 _outlive: outlive,
716 })
717 }
718
719 fn open_raw(
720 opts: &Options,
721 cpath: &CString,
722 access_type: &AccessType,
723 ) -> Result<*mut ffi::rocksdb_t, Error> {
724 let db = unsafe {
725 match *access_type {
726 AccessType::ReadOnly {
727 error_if_log_file_exist,
728 } => ffi_try!(ffi::rocksdb_open_for_read_only(
729 opts.inner,
730 cpath.as_ptr(),
731 c_uchar::from(error_if_log_file_exist),
732 )),
733 AccessType::ReadWrite => {
734 ffi_try!(ffi::rocksdb_open(opts.inner, cpath.as_ptr()))
735 }
736 AccessType::Secondary { secondary_path } => {
737 ffi_try!(ffi::rocksdb_open_as_secondary(
738 opts.inner,
739 cpath.as_ptr(),
740 to_cpath(secondary_path)?.as_ptr(),
741 ))
742 }
743 AccessType::WithTTL { ttl } => ffi_try!(ffi::rocksdb_open_with_ttl(
744 opts.inner,
745 cpath.as_ptr(),
746 ttl.as_secs() as c_int,
747 )),
748 }
749 };
750 Ok(db)
751 }
752
753 #[allow(clippy::pedantic)]
754 fn open_cf_raw(
755 opts: &Options,
756 cpath: &CString,
757 cfs_v: &[ColumnFamilyDescriptor],
758 cfnames: &[*const c_char],
759 cfopts: &[*const ffi::rocksdb_options_t],
760 cfhandles: &mut [*mut ffi::rocksdb_column_family_handle_t],
761 access_type: &AccessType,
762 ) -> Result<*mut ffi::rocksdb_t, Error> {
763 let db = unsafe {
764 match *access_type {
765 AccessType::ReadOnly {
766 error_if_log_file_exist,
767 } => ffi_try!(ffi::rocksdb_open_for_read_only_column_families(
768 opts.inner,
769 cpath.as_ptr(),
770 cfs_v.len() as c_int,
771 cfnames.as_ptr(),
772 cfopts.as_ptr(),
773 cfhandles.as_mut_ptr(),
774 c_uchar::from(error_if_log_file_exist),
775 )),
776 AccessType::ReadWrite => ffi_try!(ffi::rocksdb_open_column_families(
777 opts.inner,
778 cpath.as_ptr(),
779 cfs_v.len() as c_int,
780 cfnames.as_ptr(),
781 cfopts.as_ptr(),
782 cfhandles.as_mut_ptr(),
783 )),
784 AccessType::Secondary { secondary_path } => {
785 ffi_try!(ffi::rocksdb_open_as_secondary_column_families(
786 opts.inner,
787 cpath.as_ptr(),
788 to_cpath(secondary_path)?.as_ptr(),
789 cfs_v.len() as c_int,
790 cfnames.as_ptr(),
791 cfopts.as_ptr(),
792 cfhandles.as_mut_ptr(),
793 ))
794 }
795 AccessType::WithTTL { ttl } => {
796 let ttls: Vec<_> = cfs_v
797 .iter()
798 .map(|cf| match cf.ttl {
799 ColumnFamilyTtl::Disabled => i32::MAX,
800 ColumnFamilyTtl::Duration(duration) => duration.as_secs() as i32,
801 ColumnFamilyTtl::SameAsDb => ttl.as_secs() as i32,
802 })
803 .collect();
804
805 ffi_try!(ffi::rocksdb_open_column_families_with_ttl(
806 opts.inner,
807 cpath.as_ptr(),
808 cfs_v.len() as c_int,
809 cfnames.as_ptr(),
810 cfopts.as_ptr(),
811 cfhandles.as_mut_ptr(),
812 ttls.as_ptr(),
813 ))
814 }
815 }
816 };
817 Ok(db)
818 }
819
820 pub fn delete_range_cf_opt<K: AsRef<[u8]>>(
822 &self,
823 cf: &impl AsColumnFamilyRef,
824 from: K,
825 to: K,
826 writeopts: &WriteOptions,
827 ) -> Result<(), Error> {
828 let from = from.as_ref();
829 let to = to.as_ref();
830
831 unsafe {
832 ffi_try!(ffi::rocksdb_delete_range_cf(
833 self.inner.inner(),
834 writeopts.inner,
835 cf.inner(),
836 from.as_ptr() as *const c_char,
837 from.len() as size_t,
838 to.as_ptr() as *const c_char,
839 to.len() as size_t,
840 ));
841 Ok(())
842 }
843 }
844
845 pub fn delete_range_cf<K: AsRef<[u8]>>(
847 &self,
848 cf: &impl AsColumnFamilyRef,
849 from: K,
850 to: K,
851 ) -> Result<(), Error> {
852 self.delete_range_cf_opt(cf, from, to, &WriteOptions::default())
853 }
854
855 pub fn write_opt(&self, batch: WriteBatch, writeopts: &WriteOptions) -> Result<(), Error> {
856 unsafe {
857 ffi_try!(ffi::rocksdb_write(
858 self.inner.inner(),
859 writeopts.inner,
860 batch.inner
861 ));
862 }
863 Ok(())
864 }
865
866 pub fn write(&self, batch: WriteBatch) -> Result<(), Error> {
867 self.write_opt(batch, &WriteOptions::default())
868 }
869
870 pub fn write_without_wal(&self, batch: WriteBatch) -> Result<(), Error> {
871 let mut wo = WriteOptions::new();
872 wo.disable_wal(true);
873 self.write_opt(batch, &wo)
874 }
875
876 pub fn disable_file_deletions(&self) -> Result<(), Error> {
881 unsafe {
882 ffi_try!(ffi::rocksdb_disable_file_deletions(self.inner.inner()));
883 }
884 Ok(())
885 }
886
887 pub fn enable_file_deletions(&self) -> Result<(), Error> {
899 unsafe {
900 ffi_try!(ffi::rocksdb_enable_file_deletions(self.inner.inner()));
901 }
902 Ok(())
903 }
904}
905
906impl<T: ThreadMode, D: DBInner> DBCommon<T, D> {
908 pub(crate) fn new(inner: D, cfs: T, path: PathBuf, outlive: Vec<OptionsMustOutliveDB>) -> Self {
909 Self {
910 inner,
911 cfs,
912 path,
913 _outlive: outlive,
914 }
915 }
916
917 pub fn list_cf<P: AsRef<Path>>(opts: &Options, path: P) -> Result<Vec<String>, Error> {
918 let cpath = to_cpath(path)?;
919 let mut length = 0;
920
921 unsafe {
922 let ptr = ffi_try!(ffi::rocksdb_list_column_families(
923 opts.inner,
924 cpath.as_ptr(),
925 &raw mut length,
926 ));
927
928 let vec = slice::from_raw_parts(ptr, length)
929 .iter()
930 .map(|ptr| from_cstr_without_free(*ptr))
931 .collect();
932 ffi::rocksdb_list_column_families_destroy(ptr, length);
933 Ok(vec)
934 }
935 }
936
937 pub fn destroy<P: AsRef<Path>>(opts: &Options, path: P) -> Result<(), Error> {
938 let cpath = to_cpath(path)?;
939 unsafe {
940 ffi_try!(ffi::rocksdb_destroy_db(opts.inner, cpath.as_ptr()));
941 }
942 Ok(())
943 }
944
945 pub fn repair<P: AsRef<Path>>(opts: &Options, path: P) -> Result<(), Error> {
946 let cpath = to_cpath(path)?;
947 unsafe {
948 ffi_try!(ffi::rocksdb_repair_db(opts.inner, cpath.as_ptr()));
949 }
950 Ok(())
951 }
952
953 pub fn path(&self) -> &Path {
954 self.path.as_path()
955 }
956
957 pub fn flush_wal(&self, sync: bool) -> Result<(), Error> {
960 unsafe {
961 ffi_try!(ffi::rocksdb_flush_wal(
962 self.inner.inner(),
963 c_uchar::from(sync)
964 ));
965 }
966 Ok(())
967 }
968
969 pub fn flush_opt(&self, flushopts: &FlushOptions) -> Result<(), Error> {
971 unsafe {
972 ffi_try!(ffi::rocksdb_flush(self.inner.inner(), flushopts.inner));
973 }
974 Ok(())
975 }
976
977 pub fn flush(&self) -> Result<(), Error> {
979 self.flush_opt(&FlushOptions::default())
980 }
981
982 pub fn flush_cf_opt(
984 &self,
985 cf: &impl AsColumnFamilyRef,
986 flushopts: &FlushOptions,
987 ) -> Result<(), Error> {
988 unsafe {
989 ffi_try!(ffi::rocksdb_flush_cf(
990 self.inner.inner(),
991 flushopts.inner,
992 cf.inner()
993 ));
994 }
995 Ok(())
996 }
997
998 pub fn flush_cfs_opt(
1004 &self,
1005 cfs: &[&impl AsColumnFamilyRef],
1006 opts: &FlushOptions,
1007 ) -> Result<(), Error> {
1008 let mut cfs = cfs.iter().map(|cf| cf.inner()).collect::<Vec<_>>();
1009 unsafe {
1010 ffi_try!(ffi::rocksdb_flush_cfs(
1011 self.inner.inner(),
1012 opts.inner,
1013 cfs.as_mut_ptr(),
1014 cfs.len() as libc::c_int,
1015 ));
1016 }
1017 Ok(())
1018 }
1019
1020 pub fn flush_cf(&self, cf: &impl AsColumnFamilyRef) -> Result<(), Error> {
1023 self.flush_cf_opt(cf, &FlushOptions::default())
1024 }
1025
1026 pub fn get_opt<K: AsRef<[u8]>>(
1030 &self,
1031 key: K,
1032 readopts: &ReadOptions,
1033 ) -> Result<Option<Vec<u8>>, Error> {
1034 self.get_pinned_opt(key, readopts)
1035 .map(|x| x.map(|v| v.as_ref().to_vec()))
1036 }
1037
1038 pub fn get<K: AsRef<[u8]>>(&self, key: K) -> Result<Option<Vec<u8>>, Error> {
1042 self.get_opt(key.as_ref(), &ReadOptions::default())
1043 }
1044
1045 pub fn get_cf_opt<K: AsRef<[u8]>>(
1049 &self,
1050 cf: &impl AsColumnFamilyRef,
1051 key: K,
1052 readopts: &ReadOptions,
1053 ) -> Result<Option<Vec<u8>>, Error> {
1054 self.get_pinned_cf_opt(cf, key, readopts)
1055 .map(|x| x.map(|v| v.as_ref().to_vec()))
1056 }
1057
1058 pub fn get_cf<K: AsRef<[u8]>>(
1062 &self,
1063 cf: &impl AsColumnFamilyRef,
1064 key: K,
1065 ) -> Result<Option<Vec<u8>>, Error> {
1066 self.get_cf_opt(cf, key.as_ref(), &ReadOptions::default())
1067 }
1068
1069 pub fn get_pinned_opt<K: AsRef<[u8]>>(
1072 &self,
1073 key: K,
1074 readopts: &ReadOptions,
1075 ) -> Result<Option<DBPinnableSlice>, Error> {
1076 if readopts.inner.is_null() {
1077 return Err(Error::new(
1078 "Unable to create RocksDB read options. This is a fairly trivial call, and its \
1079 failure may be indicative of a mis-compiled or mis-loaded RocksDB library."
1080 .to_owned(),
1081 ));
1082 }
1083
1084 let key = key.as_ref();
1085 unsafe {
1086 let val = ffi_try!(ffi::rocksdb_get_pinned(
1087 self.inner.inner(),
1088 readopts.inner,
1089 key.as_ptr() as *const c_char,
1090 key.len() as size_t,
1091 ));
1092 if val.is_null() {
1093 Ok(None)
1094 } else {
1095 Ok(Some(DBPinnableSlice::from_c(val)))
1096 }
1097 }
1098 }
1099
1100 pub fn get_pinned<K: AsRef<[u8]>>(&self, key: K) -> Result<Option<DBPinnableSlice>, Error> {
1104 self.get_pinned_opt(key, &ReadOptions::default())
1105 }
1106
1107 pub fn get_pinned_cf_opt<K: AsRef<[u8]>>(
1111 &self,
1112 cf: &impl AsColumnFamilyRef,
1113 key: K,
1114 readopts: &ReadOptions,
1115 ) -> Result<Option<DBPinnableSlice>, Error> {
1116 if readopts.inner.is_null() {
1117 return Err(Error::new(
1118 "Unable to create RocksDB read options. This is a fairly trivial call, and its \
1119 failure may be indicative of a mis-compiled or mis-loaded RocksDB library."
1120 .to_owned(),
1121 ));
1122 }
1123
1124 let key = key.as_ref();
1125 unsafe {
1126 let val = ffi_try!(ffi::rocksdb_get_pinned_cf(
1127 self.inner.inner(),
1128 readopts.inner,
1129 cf.inner(),
1130 key.as_ptr() as *const c_char,
1131 key.len() as size_t,
1132 ));
1133 if val.is_null() {
1134 Ok(None)
1135 } else {
1136 Ok(Some(DBPinnableSlice::from_c(val)))
1137 }
1138 }
1139 }
1140
1141 pub fn get_pinned_cf<K: AsRef<[u8]>>(
1145 &self,
1146 cf: &impl AsColumnFamilyRef,
1147 key: K,
1148 ) -> Result<Option<DBPinnableSlice>, Error> {
1149 self.get_pinned_cf_opt(cf, key, &ReadOptions::default())
1150 }
1151
1152 pub fn multi_get<K, I>(&self, keys: I) -> Vec<Result<Option<Vec<u8>>, Error>>
1154 where
1155 K: AsRef<[u8]>,
1156 I: IntoIterator<Item = K>,
1157 {
1158 self.multi_get_opt(keys, &ReadOptions::default())
1159 }
1160
1161 pub fn multi_get_opt<K, I>(
1163 &self,
1164 keys: I,
1165 readopts: &ReadOptions,
1166 ) -> Vec<Result<Option<Vec<u8>>, Error>>
1167 where
1168 K: AsRef<[u8]>,
1169 I: IntoIterator<Item = K>,
1170 {
1171 let (keys, keys_sizes): (Vec<Box<[u8]>>, Vec<_>) = keys
1172 .into_iter()
1173 .map(|k| {
1174 let k = k.as_ref();
1175 (Box::from(k), k.len())
1176 })
1177 .unzip();
1178 let ptr_keys: Vec<_> = keys.iter().map(|k| k.as_ptr() as *const c_char).collect();
1179
1180 let mut values = vec![ptr::null_mut(); keys.len()];
1181 let mut values_sizes = vec![0_usize; keys.len()];
1182 let mut errors = vec![ptr::null_mut(); keys.len()];
1183 unsafe {
1184 ffi::rocksdb_multi_get(
1185 self.inner.inner(),
1186 readopts.inner,
1187 ptr_keys.len(),
1188 ptr_keys.as_ptr(),
1189 keys_sizes.as_ptr(),
1190 values.as_mut_ptr(),
1191 values_sizes.as_mut_ptr(),
1192 errors.as_mut_ptr(),
1193 );
1194 }
1195
1196 convert_values(values, values_sizes, errors)
1197 }
1198
1199 pub fn multi_get_cf<'a, 'b: 'a, K, I, W>(
1201 &'a self,
1202 keys: I,
1203 ) -> Vec<Result<Option<Vec<u8>>, Error>>
1204 where
1205 K: AsRef<[u8]>,
1206 I: IntoIterator<Item = (&'b W, K)>,
1207 W: 'b + AsColumnFamilyRef,
1208 {
1209 self.multi_get_cf_opt(keys, &ReadOptions::default())
1210 }
1211
1212 pub fn multi_get_cf_opt<'a, 'b: 'a, K, I, W>(
1214 &'a self,
1215 keys: I,
1216 readopts: &ReadOptions,
1217 ) -> Vec<Result<Option<Vec<u8>>, Error>>
1218 where
1219 K: AsRef<[u8]>,
1220 I: IntoIterator<Item = (&'b W, K)>,
1221 W: 'b + AsColumnFamilyRef,
1222 {
1223 let (cfs_and_keys, keys_sizes): (Vec<(_, Box<[u8]>)>, Vec<_>) = keys
1224 .into_iter()
1225 .map(|(cf, key)| {
1226 let key = key.as_ref();
1227 ((cf, Box::from(key)), key.len())
1228 })
1229 .unzip();
1230 let ptr_keys: Vec<_> = cfs_and_keys
1231 .iter()
1232 .map(|(_, k)| k.as_ptr() as *const c_char)
1233 .collect();
1234 let ptr_cfs: Vec<_> = cfs_and_keys
1235 .iter()
1236 .map(|(c, _)| c.inner().cast_const())
1237 .collect();
1238
1239 let mut values = vec![ptr::null_mut(); ptr_keys.len()];
1240 let mut values_sizes = vec![0_usize; ptr_keys.len()];
1241 let mut errors = vec![ptr::null_mut(); ptr_keys.len()];
1242 unsafe {
1243 ffi::rocksdb_multi_get_cf(
1244 self.inner.inner(),
1245 readopts.inner,
1246 ptr_cfs.as_ptr(),
1247 ptr_keys.len(),
1248 ptr_keys.as_ptr(),
1249 keys_sizes.as_ptr(),
1250 values.as_mut_ptr(),
1251 values_sizes.as_mut_ptr(),
1252 errors.as_mut_ptr(),
1253 );
1254 }
1255
1256 convert_values(values, values_sizes, errors)
1257 }
1258
1259 pub fn batched_multi_get_cf<'a, K, I>(
1263 &self,
1264 cf: &impl AsColumnFamilyRef,
1265 keys: I,
1266 sorted_input: bool,
1267 ) -> Vec<Result<Option<DBPinnableSlice>, Error>>
1268 where
1269 K: AsRef<[u8]> + 'a + ?Sized,
1270 I: IntoIterator<Item = &'a K>,
1271 {
1272 self.batched_multi_get_cf_opt(cf, keys, sorted_input, &ReadOptions::default())
1273 }
1274
1275 pub fn batched_multi_get_cf_opt<'a, K, I>(
1279 &self,
1280 cf: &impl AsColumnFamilyRef,
1281 keys: I,
1282 sorted_input: bool,
1283 readopts: &ReadOptions,
1284 ) -> Vec<Result<Option<DBPinnableSlice>, Error>>
1285 where
1286 K: AsRef<[u8]> + 'a + ?Sized,
1287 I: IntoIterator<Item = &'a K>,
1288 {
1289 let (ptr_keys, keys_sizes): (Vec<_>, Vec<_>) = keys
1290 .into_iter()
1291 .map(|k| {
1292 let k = k.as_ref();
1293 (k.as_ptr() as *const c_char, k.len())
1294 })
1295 .unzip();
1296
1297 let mut pinned_values = vec![ptr::null_mut(); ptr_keys.len()];
1298 let mut errors = vec![ptr::null_mut(); ptr_keys.len()];
1299
1300 unsafe {
1301 ffi::rocksdb_batched_multi_get_cf(
1302 self.inner.inner(),
1303 readopts.inner,
1304 cf.inner(),
1305 ptr_keys.len(),
1306 ptr_keys.as_ptr(),
1307 keys_sizes.as_ptr(),
1308 pinned_values.as_mut_ptr(),
1309 errors.as_mut_ptr(),
1310 sorted_input,
1311 );
1312 pinned_values
1313 .into_iter()
1314 .zip(errors)
1315 .map(|(v, e)| {
1316 if e.is_null() {
1317 if v.is_null() {
1318 Ok(None)
1319 } else {
1320 Ok(Some(DBPinnableSlice::from_c(v)))
1321 }
1322 } else {
1323 Err(convert_rocksdb_error(e))
1324 }
1325 })
1326 .collect()
1327 }
1328 }
1329
1330 pub fn key_may_exist<K: AsRef<[u8]>>(&self, key: K) -> bool {
1333 self.key_may_exist_opt(key, &ReadOptions::default())
1334 }
1335
1336 pub fn key_may_exist_opt<K: AsRef<[u8]>>(&self, key: K, readopts: &ReadOptions) -> bool {
1339 let key = key.as_ref();
1340 unsafe {
1341 0 != ffi::rocksdb_key_may_exist(
1342 self.inner.inner(),
1343 readopts.inner,
1344 key.as_ptr() as *const c_char,
1345 key.len() as size_t,
1346 ptr::null_mut(), ptr::null_mut(), ptr::null(), 0, ptr::null_mut(), )
1352 }
1353 }
1354
1355 pub fn key_may_exist_cf<K: AsRef<[u8]>>(&self, cf: &impl AsColumnFamilyRef, key: K) -> bool {
1358 self.key_may_exist_cf_opt(cf, key, &ReadOptions::default())
1359 }
1360
1361 pub fn key_may_exist_cf_opt<K: AsRef<[u8]>>(
1364 &self,
1365 cf: &impl AsColumnFamilyRef,
1366 key: K,
1367 readopts: &ReadOptions,
1368 ) -> bool {
1369 let key = key.as_ref();
1370 0 != unsafe {
1371 ffi::rocksdb_key_may_exist_cf(
1372 self.inner.inner(),
1373 readopts.inner,
1374 cf.inner(),
1375 key.as_ptr() as *const c_char,
1376 key.len() as size_t,
1377 ptr::null_mut(), ptr::null_mut(), ptr::null(), 0, ptr::null_mut(), )
1383 }
1384 }
1385
1386 pub fn key_may_exist_cf_opt_value<K: AsRef<[u8]>>(
1393 &self,
1394 cf: &impl AsColumnFamilyRef,
1395 key: K,
1396 readopts: &ReadOptions,
1397 ) -> (bool, Option<CSlice>) {
1398 let key = key.as_ref();
1399 let mut val: *mut c_char = ptr::null_mut();
1400 let mut val_len: usize = 0;
1401 let mut value_found: c_uchar = 0;
1402 let may_exists = 0
1403 != unsafe {
1404 ffi::rocksdb_key_may_exist_cf(
1405 self.inner.inner(),
1406 readopts.inner,
1407 cf.inner(),
1408 key.as_ptr() as *const c_char,
1409 key.len() as size_t,
1410 &raw mut val, &raw mut val_len, ptr::null(), 0, &raw mut value_found, )
1416 };
1417 if may_exists && value_found != 0 {
1420 (
1421 may_exists,
1422 Some(unsafe { CSlice::from_raw_parts(val, val_len) }),
1423 )
1424 } else {
1425 (may_exists, None)
1426 }
1427 }
1428
1429 fn create_inner_cf_handle(
1430 &self,
1431 name: impl CStrLike,
1432 opts: &Options,
1433 ) -> Result<*mut ffi::rocksdb_column_family_handle_t, Error> {
1434 let cf_name = name.bake().map_err(|err| {
1435 Error::new(format!(
1436 "Failed to convert path to CString when creating cf: {err}"
1437 ))
1438 })?;
1439
1440 let mut err: *mut ::libc::c_char = ::std::ptr::null_mut();
1443 let cf_handle = unsafe {
1444 ffi::rocksdb_create_column_family(
1445 self.inner.inner(),
1446 opts.inner,
1447 cf_name.as_ptr(),
1448 &raw mut err,
1449 )
1450 };
1451 if !err.is_null() {
1452 if !cf_handle.is_null() {
1453 unsafe { ffi::rocksdb_column_family_handle_destroy(cf_handle) };
1454 }
1455 return Err(convert_rocksdb_error(err));
1456 }
1457 Ok(cf_handle)
1458 }
1459
1460 pub fn iterator<'a: 'b, 'b>(
1461 &'a self,
1462 mode: IteratorMode,
1463 ) -> DBIteratorWithThreadMode<'b, Self> {
1464 let readopts = ReadOptions::default();
1465 self.iterator_opt(mode, readopts)
1466 }
1467
1468 pub fn iterator_opt<'a: 'b, 'b>(
1469 &'a self,
1470 mode: IteratorMode,
1471 readopts: ReadOptions,
1472 ) -> DBIteratorWithThreadMode<'b, Self> {
1473 DBIteratorWithThreadMode::new(self, readopts, mode)
1474 }
1475
1476 pub fn iterator_cf_opt<'a: 'b, 'b>(
1479 &'a self,
1480 cf_handle: &impl AsColumnFamilyRef,
1481 readopts: ReadOptions,
1482 mode: IteratorMode,
1483 ) -> DBIteratorWithThreadMode<'b, Self> {
1484 DBIteratorWithThreadMode::new_cf(self, cf_handle.inner(), readopts, mode)
1485 }
1486
1487 pub fn full_iterator<'a: 'b, 'b>(
1491 &'a self,
1492 mode: IteratorMode,
1493 ) -> DBIteratorWithThreadMode<'b, Self> {
1494 let mut opts = ReadOptions::default();
1495 opts.set_total_order_seek(true);
1496 DBIteratorWithThreadMode::new(self, opts, mode)
1497 }
1498
1499 pub fn prefix_iterator<'a: 'b, 'b, P: AsRef<[u8]>>(
1500 &'a self,
1501 prefix: P,
1502 ) -> DBIteratorWithThreadMode<'b, Self> {
1503 let mut opts = ReadOptions::default();
1504 opts.set_prefix_same_as_start(true);
1505 DBIteratorWithThreadMode::new(
1506 self,
1507 opts,
1508 IteratorMode::From(prefix.as_ref(), Direction::Forward),
1509 )
1510 }
1511
1512 pub fn iterator_cf<'a: 'b, 'b>(
1513 &'a self,
1514 cf_handle: &impl AsColumnFamilyRef,
1515 mode: IteratorMode,
1516 ) -> DBIteratorWithThreadMode<'b, Self> {
1517 let opts = ReadOptions::default();
1518 DBIteratorWithThreadMode::new_cf(self, cf_handle.inner(), opts, mode)
1519 }
1520
1521 pub fn full_iterator_cf<'a: 'b, 'b>(
1522 &'a self,
1523 cf_handle: &impl AsColumnFamilyRef,
1524 mode: IteratorMode,
1525 ) -> DBIteratorWithThreadMode<'b, Self> {
1526 let mut opts = ReadOptions::default();
1527 opts.set_total_order_seek(true);
1528 DBIteratorWithThreadMode::new_cf(self, cf_handle.inner(), opts, mode)
1529 }
1530
1531 pub fn prefix_iterator_cf<'a, P: AsRef<[u8]>>(
1532 &'a self,
1533 cf_handle: &impl AsColumnFamilyRef,
1534 prefix: P,
1535 ) -> DBIteratorWithThreadMode<'a, Self> {
1536 let mut opts = ReadOptions::default();
1537 opts.set_prefix_same_as_start(true);
1538 DBIteratorWithThreadMode::<'a, Self>::new_cf(
1539 self,
1540 cf_handle.inner(),
1541 opts,
1542 IteratorMode::From(prefix.as_ref(), Direction::Forward),
1543 )
1544 }
1545
1546 pub fn raw_iterator<'a: 'b, 'b>(&'a self) -> DBRawIteratorWithThreadMode<'b, Self> {
1548 let opts = ReadOptions::default();
1549 DBRawIteratorWithThreadMode::new(self, opts)
1550 }
1551
1552 pub fn raw_iterator_cf<'a: 'b, 'b>(
1554 &'a self,
1555 cf_handle: &impl AsColumnFamilyRef,
1556 ) -> DBRawIteratorWithThreadMode<'b, Self> {
1557 let opts = ReadOptions::default();
1558 DBRawIteratorWithThreadMode::new_cf(self, cf_handle.inner(), opts)
1559 }
1560
1561 pub fn raw_iterator_opt<'a: 'b, 'b>(
1563 &'a self,
1564 readopts: ReadOptions,
1565 ) -> DBRawIteratorWithThreadMode<'b, Self> {
1566 DBRawIteratorWithThreadMode::new(self, readopts)
1567 }
1568
1569 pub fn raw_iterator_cf_opt<'a: 'b, 'b>(
1571 &'a self,
1572 cf_handle: &impl AsColumnFamilyRef,
1573 readopts: ReadOptions,
1574 ) -> DBRawIteratorWithThreadMode<'b, Self> {
1575 DBRawIteratorWithThreadMode::new_cf(self, cf_handle.inner(), readopts)
1576 }
1577
1578 pub fn snapshot(&self) -> SnapshotWithThreadMode<Self> {
1579 SnapshotWithThreadMode::<Self>::new(self)
1580 }
1581
1582 pub fn put_opt<K, V>(&self, key: K, value: V, writeopts: &WriteOptions) -> Result<(), Error>
1583 where
1584 K: AsRef<[u8]>,
1585 V: AsRef<[u8]>,
1586 {
1587 let key = key.as_ref();
1588 let value = value.as_ref();
1589
1590 unsafe {
1591 ffi_try!(ffi::rocksdb_put(
1592 self.inner.inner(),
1593 writeopts.inner,
1594 key.as_ptr() as *const c_char,
1595 key.len() as size_t,
1596 value.as_ptr() as *const c_char,
1597 value.len() as size_t,
1598 ));
1599 Ok(())
1600 }
1601 }
1602
1603 pub fn put_cf_opt<K, V>(
1604 &self,
1605 cf: &impl AsColumnFamilyRef,
1606 key: K,
1607 value: V,
1608 writeopts: &WriteOptions,
1609 ) -> Result<(), Error>
1610 where
1611 K: AsRef<[u8]>,
1612 V: AsRef<[u8]>,
1613 {
1614 let key = key.as_ref();
1615 let value = value.as_ref();
1616
1617 unsafe {
1618 ffi_try!(ffi::rocksdb_put_cf(
1619 self.inner.inner(),
1620 writeopts.inner,
1621 cf.inner(),
1622 key.as_ptr() as *const c_char,
1623 key.len() as size_t,
1624 value.as_ptr() as *const c_char,
1625 value.len() as size_t,
1626 ));
1627 Ok(())
1628 }
1629 }
1630
1631 pub fn put_with_ts_opt<K, V, S>(
1638 &self,
1639 key: K,
1640 ts: S,
1641 value: V,
1642 writeopts: &WriteOptions,
1643 ) -> Result<(), Error>
1644 where
1645 K: AsRef<[u8]>,
1646 V: AsRef<[u8]>,
1647 S: AsRef<[u8]>,
1648 {
1649 let key = key.as_ref();
1650 let value = value.as_ref();
1651 let ts = ts.as_ref();
1652 unsafe {
1653 ffi_try!(ffi::rocksdb_put_with_ts(
1654 self.inner.inner(),
1655 writeopts.inner,
1656 key.as_ptr() as *const c_char,
1657 key.len() as size_t,
1658 ts.as_ptr() as *const c_char,
1659 ts.len() as size_t,
1660 value.as_ptr() as *const c_char,
1661 value.len() as size_t,
1662 ));
1663 Ok(())
1664 }
1665 }
1666
1667 pub fn put_cf_with_ts_opt<K, V, S>(
1674 &self,
1675 cf: &impl AsColumnFamilyRef,
1676 key: K,
1677 ts: S,
1678 value: V,
1679 writeopts: &WriteOptions,
1680 ) -> Result<(), Error>
1681 where
1682 K: AsRef<[u8]>,
1683 V: AsRef<[u8]>,
1684 S: AsRef<[u8]>,
1685 {
1686 let key = key.as_ref();
1687 let value = value.as_ref();
1688 let ts = ts.as_ref();
1689 unsafe {
1690 ffi_try!(ffi::rocksdb_put_cf_with_ts(
1691 self.inner.inner(),
1692 writeopts.inner,
1693 cf.inner(),
1694 key.as_ptr() as *const c_char,
1695 key.len() as size_t,
1696 ts.as_ptr() as *const c_char,
1697 ts.len() as size_t,
1698 value.as_ptr() as *const c_char,
1699 value.len() as size_t,
1700 ));
1701 Ok(())
1702 }
1703 }
1704
1705 pub fn merge_opt<K, V>(&self, key: K, value: V, writeopts: &WriteOptions) -> Result<(), Error>
1706 where
1707 K: AsRef<[u8]>,
1708 V: AsRef<[u8]>,
1709 {
1710 let key = key.as_ref();
1711 let value = value.as_ref();
1712
1713 unsafe {
1714 ffi_try!(ffi::rocksdb_merge(
1715 self.inner.inner(),
1716 writeopts.inner,
1717 key.as_ptr() as *const c_char,
1718 key.len() as size_t,
1719 value.as_ptr() as *const c_char,
1720 value.len() as size_t,
1721 ));
1722 Ok(())
1723 }
1724 }
1725
1726 pub fn merge_cf_opt<K, V>(
1727 &self,
1728 cf: &impl AsColumnFamilyRef,
1729 key: K,
1730 value: V,
1731 writeopts: &WriteOptions,
1732 ) -> Result<(), Error>
1733 where
1734 K: AsRef<[u8]>,
1735 V: AsRef<[u8]>,
1736 {
1737 let key = key.as_ref();
1738 let value = value.as_ref();
1739
1740 unsafe {
1741 ffi_try!(ffi::rocksdb_merge_cf(
1742 self.inner.inner(),
1743 writeopts.inner,
1744 cf.inner(),
1745 key.as_ptr() as *const c_char,
1746 key.len() as size_t,
1747 value.as_ptr() as *const c_char,
1748 value.len() as size_t,
1749 ));
1750 Ok(())
1751 }
1752 }
1753
1754 pub fn delete_opt<K: AsRef<[u8]>>(
1755 &self,
1756 key: K,
1757 writeopts: &WriteOptions,
1758 ) -> Result<(), Error> {
1759 let key = key.as_ref();
1760
1761 unsafe {
1762 ffi_try!(ffi::rocksdb_delete(
1763 self.inner.inner(),
1764 writeopts.inner,
1765 key.as_ptr() as *const c_char,
1766 key.len() as size_t,
1767 ));
1768 Ok(())
1769 }
1770 }
1771
1772 pub fn delete_cf_opt<K: AsRef<[u8]>>(
1773 &self,
1774 cf: &impl AsColumnFamilyRef,
1775 key: K,
1776 writeopts: &WriteOptions,
1777 ) -> Result<(), Error> {
1778 let key = key.as_ref();
1779
1780 unsafe {
1781 ffi_try!(ffi::rocksdb_delete_cf(
1782 self.inner.inner(),
1783 writeopts.inner,
1784 cf.inner(),
1785 key.as_ptr() as *const c_char,
1786 key.len() as size_t,
1787 ));
1788 Ok(())
1789 }
1790 }
1791
1792 pub fn delete_with_ts_opt<K, S>(
1796 &self,
1797 key: K,
1798 ts: S,
1799 writeopts: &WriteOptions,
1800 ) -> Result<(), Error>
1801 where
1802 K: AsRef<[u8]>,
1803 S: AsRef<[u8]>,
1804 {
1805 let key = key.as_ref();
1806 let ts = ts.as_ref();
1807 unsafe {
1808 ffi_try!(ffi::rocksdb_delete_with_ts(
1809 self.inner.inner(),
1810 writeopts.inner,
1811 key.as_ptr() as *const c_char,
1812 key.len() as size_t,
1813 ts.as_ptr() as *const c_char,
1814 ts.len() as size_t,
1815 ));
1816 Ok(())
1817 }
1818 }
1819
1820 pub fn delete_cf_with_ts_opt<K, S>(
1824 &self,
1825 cf: &impl AsColumnFamilyRef,
1826 key: K,
1827 ts: S,
1828 writeopts: &WriteOptions,
1829 ) -> Result<(), Error>
1830 where
1831 K: AsRef<[u8]>,
1832 S: AsRef<[u8]>,
1833 {
1834 let key = key.as_ref();
1835 let ts = ts.as_ref();
1836 unsafe {
1837 ffi_try!(ffi::rocksdb_delete_cf_with_ts(
1838 self.inner.inner(),
1839 writeopts.inner,
1840 cf.inner(),
1841 key.as_ptr() as *const c_char,
1842 key.len() as size_t,
1843 ts.as_ptr() as *const c_char,
1844 ts.len() as size_t,
1845 ));
1846 Ok(())
1847 }
1848 }
1849
1850 pub fn put<K, V>(&self, key: K, value: V) -> Result<(), Error>
1851 where
1852 K: AsRef<[u8]>,
1853 V: AsRef<[u8]>,
1854 {
1855 self.put_opt(key.as_ref(), value.as_ref(), &WriteOptions::default())
1856 }
1857
1858 pub fn put_cf<K, V>(&self, cf: &impl AsColumnFamilyRef, key: K, value: V) -> Result<(), Error>
1859 where
1860 K: AsRef<[u8]>,
1861 V: AsRef<[u8]>,
1862 {
1863 self.put_cf_opt(cf, key.as_ref(), value.as_ref(), &WriteOptions::default())
1864 }
1865
1866 pub fn put_with_ts<K, V, S>(&self, key: K, ts: S, value: V) -> Result<(), Error>
1873 where
1874 K: AsRef<[u8]>,
1875 V: AsRef<[u8]>,
1876 S: AsRef<[u8]>,
1877 {
1878 self.put_with_ts_opt(
1879 key.as_ref(),
1880 ts.as_ref(),
1881 value.as_ref(),
1882 &WriteOptions::default(),
1883 )
1884 }
1885
1886 pub fn put_cf_with_ts<K, V, S>(
1893 &self,
1894 cf: &impl AsColumnFamilyRef,
1895 key: K,
1896 ts: S,
1897 value: V,
1898 ) -> Result<(), Error>
1899 where
1900 K: AsRef<[u8]>,
1901 V: AsRef<[u8]>,
1902 S: AsRef<[u8]>,
1903 {
1904 self.put_cf_with_ts_opt(
1905 cf,
1906 key.as_ref(),
1907 ts.as_ref(),
1908 value.as_ref(),
1909 &WriteOptions::default(),
1910 )
1911 }
1912
1913 pub fn merge<K, V>(&self, key: K, value: V) -> Result<(), Error>
1914 where
1915 K: AsRef<[u8]>,
1916 V: AsRef<[u8]>,
1917 {
1918 self.merge_opt(key.as_ref(), value.as_ref(), &WriteOptions::default())
1919 }
1920
1921 pub fn merge_cf<K, V>(&self, cf: &impl AsColumnFamilyRef, key: K, value: V) -> Result<(), Error>
1922 where
1923 K: AsRef<[u8]>,
1924 V: AsRef<[u8]>,
1925 {
1926 self.merge_cf_opt(cf, key.as_ref(), value.as_ref(), &WriteOptions::default())
1927 }
1928
1929 pub fn delete<K: AsRef<[u8]>>(&self, key: K) -> Result<(), Error> {
1930 self.delete_opt(key.as_ref(), &WriteOptions::default())
1931 }
1932
1933 pub fn delete_cf<K: AsRef<[u8]>>(
1934 &self,
1935 cf: &impl AsColumnFamilyRef,
1936 key: K,
1937 ) -> Result<(), Error> {
1938 self.delete_cf_opt(cf, key.as_ref(), &WriteOptions::default())
1939 }
1940
1941 pub fn delete_with_ts<K: AsRef<[u8]>, S: AsRef<[u8]>>(
1945 &self,
1946 key: K,
1947 ts: S,
1948 ) -> Result<(), Error> {
1949 self.delete_with_ts_opt(key.as_ref(), ts.as_ref(), &WriteOptions::default())
1950 }
1951
1952 pub fn delete_cf_with_ts<K: AsRef<[u8]>, S: AsRef<[u8]>>(
1956 &self,
1957 cf: &impl AsColumnFamilyRef,
1958 key: K,
1959 ts: S,
1960 ) -> Result<(), Error> {
1961 self.delete_cf_with_ts_opt(cf, key.as_ref(), ts.as_ref(), &WriteOptions::default())
1962 }
1963
1964 pub fn compact_range<S: AsRef<[u8]>, E: AsRef<[u8]>>(&self, start: Option<S>, end: Option<E>) {
1966 unsafe {
1967 let start = start.as_ref().map(AsRef::as_ref);
1968 let end = end.as_ref().map(AsRef::as_ref);
1969
1970 ffi::rocksdb_compact_range(
1971 self.inner.inner(),
1972 opt_bytes_to_ptr(start),
1973 start.map_or(0, <[u8]>::len) as size_t,
1974 opt_bytes_to_ptr(end),
1975 end.map_or(0, <[u8]>::len) as size_t,
1976 );
1977 }
1978 }
1979
1980 pub fn compact_range_opt<S: AsRef<[u8]>, E: AsRef<[u8]>>(
1982 &self,
1983 start: Option<S>,
1984 end: Option<E>,
1985 opts: &CompactOptions,
1986 ) {
1987 unsafe {
1988 let start = start.as_ref().map(AsRef::as_ref);
1989 let end = end.as_ref().map(AsRef::as_ref);
1990
1991 ffi::rocksdb_compact_range_opt(
1992 self.inner.inner(),
1993 opts.inner,
1994 opt_bytes_to_ptr(start),
1995 start.map_or(0, <[u8]>::len) as size_t,
1996 opt_bytes_to_ptr(end),
1997 end.map_or(0, <[u8]>::len) as size_t,
1998 );
1999 }
2000 }
2001
2002 pub fn compact_range_cf<S: AsRef<[u8]>, E: AsRef<[u8]>>(
2005 &self,
2006 cf: &impl AsColumnFamilyRef,
2007 start: Option<S>,
2008 end: Option<E>,
2009 ) {
2010 unsafe {
2011 let start = start.as_ref().map(AsRef::as_ref);
2012 let end = end.as_ref().map(AsRef::as_ref);
2013
2014 ffi::rocksdb_compact_range_cf(
2015 self.inner.inner(),
2016 cf.inner(),
2017 opt_bytes_to_ptr(start),
2018 start.map_or(0, <[u8]>::len) as size_t,
2019 opt_bytes_to_ptr(end),
2020 end.map_or(0, <[u8]>::len) as size_t,
2021 );
2022 }
2023 }
2024
2025 pub fn compact_range_cf_opt<S: AsRef<[u8]>, E: AsRef<[u8]>>(
2027 &self,
2028 cf: &impl AsColumnFamilyRef,
2029 start: Option<S>,
2030 end: Option<E>,
2031 opts: &CompactOptions,
2032 ) {
2033 unsafe {
2034 let start = start.as_ref().map(AsRef::as_ref);
2035 let end = end.as_ref().map(AsRef::as_ref);
2036
2037 ffi::rocksdb_compact_range_cf_opt(
2038 self.inner.inner(),
2039 cf.inner(),
2040 opts.inner,
2041 opt_bytes_to_ptr(start),
2042 start.map_or(0, <[u8]>::len) as size_t,
2043 opt_bytes_to_ptr(end),
2044 end.map_or(0, <[u8]>::len) as size_t,
2045 );
2046 }
2047 }
2048
2049 pub fn wait_for_compact(&self, opts: &WaitForCompactOptions) -> Result<(), Error> {
2058 unsafe {
2059 ffi_try!(ffi::rocksdb_wait_for_compact(
2060 self.inner.inner(),
2061 opts.inner
2062 ));
2063 }
2064 Ok(())
2065 }
2066
2067 pub fn set_options(&self, opts: &[(&str, &str)]) -> Result<(), Error> {
2068 let copts = convert_options(opts)?;
2069 let cnames: Vec<*const c_char> = copts.iter().map(|opt| opt.0.as_ptr()).collect();
2070 let cvalues: Vec<*const c_char> = copts.iter().map(|opt| opt.1.as_ptr()).collect();
2071 let count = opts.len() as i32;
2072 unsafe {
2073 ffi_try!(ffi::rocksdb_set_options(
2074 self.inner.inner(),
2075 count,
2076 cnames.as_ptr(),
2077 cvalues.as_ptr(),
2078 ));
2079 }
2080 Ok(())
2081 }
2082
2083 pub fn set_options_cf(
2084 &self,
2085 cf: &impl AsColumnFamilyRef,
2086 opts: &[(&str, &str)],
2087 ) -> Result<(), Error> {
2088 let copts = convert_options(opts)?;
2089 let cnames: Vec<*const c_char> = copts.iter().map(|opt| opt.0.as_ptr()).collect();
2090 let cvalues: Vec<*const c_char> = copts.iter().map(|opt| opt.1.as_ptr()).collect();
2091 let count = opts.len() as i32;
2092 unsafe {
2093 ffi_try!(ffi::rocksdb_set_options_cf(
2094 self.inner.inner(),
2095 cf.inner(),
2096 count,
2097 cnames.as_ptr(),
2098 cvalues.as_ptr(),
2099 ));
2100 }
2101 Ok(())
2102 }
2103
2104 fn property_value_impl<R>(
2113 name: impl CStrLike,
2114 get_property: impl FnOnce(*const c_char) -> *mut c_char,
2115 parse: impl FnOnce(&str) -> Result<R, Error>,
2116 ) -> Result<Option<R>, Error> {
2117 let value = match name.bake() {
2118 Ok(prop_name) => get_property(prop_name.as_ptr()),
2119 Err(e) => {
2120 return Err(Error::new(format!(
2121 "Failed to convert property name to CString: {e}"
2122 )));
2123 }
2124 };
2125 if value.is_null() {
2126 return Ok(None);
2127 }
2128 let result = match unsafe { CStr::from_ptr(value) }.to_str() {
2129 Ok(s) => parse(s).map(|value| Some(value)),
2130 Err(e) => Err(Error::new(format!(
2131 "Failed to convert property value to string: {e}"
2132 ))),
2133 };
2134 unsafe {
2135 ffi::rocksdb_free(value as *mut c_void);
2136 }
2137 result
2138 }
2139
2140 pub fn property_value(&self, name: impl CStrLike) -> Result<Option<String>, Error> {
2145 Self::property_value_impl(
2146 name,
2147 |prop_name| unsafe { ffi::rocksdb_property_value(self.inner.inner(), prop_name) },
2148 |str_value| Ok(str_value.to_owned()),
2149 )
2150 }
2151
2152 pub fn property_value_cf(
2157 &self,
2158 cf: &impl AsColumnFamilyRef,
2159 name: impl CStrLike,
2160 ) -> Result<Option<String>, Error> {
2161 Self::property_value_impl(
2162 name,
2163 |prop_name| unsafe {
2164 ffi::rocksdb_property_value_cf(self.inner.inner(), cf.inner(), prop_name)
2165 },
2166 |str_value| Ok(str_value.to_owned()),
2167 )
2168 }
2169
2170 fn parse_property_int_value(value: &str) -> Result<u64, Error> {
2171 value.parse::<u64>().map_err(|err| {
2172 Error::new(format!(
2173 "Failed to convert property value {value} to int: {err}"
2174 ))
2175 })
2176 }
2177
2178 pub fn property_int_value(&self, name: impl CStrLike) -> Result<Option<u64>, Error> {
2183 Self::property_value_impl(
2184 name,
2185 |prop_name| unsafe { ffi::rocksdb_property_value(self.inner.inner(), prop_name) },
2186 Self::parse_property_int_value,
2187 )
2188 }
2189
2190 pub fn property_int_value_cf(
2195 &self,
2196 cf: &impl AsColumnFamilyRef,
2197 name: impl CStrLike,
2198 ) -> Result<Option<u64>, Error> {
2199 Self::property_value_impl(
2200 name,
2201 |prop_name| unsafe {
2202 ffi::rocksdb_property_value_cf(self.inner.inner(), cf.inner(), prop_name)
2203 },
2204 Self::parse_property_int_value,
2205 )
2206 }
2207
2208 pub fn latest_sequence_number(&self) -> u64 {
2210 unsafe { ffi::rocksdb_get_latest_sequence_number(self.inner.inner()) }
2211 }
2212
2213 pub fn get_approximate_sizes(&self, ranges: &[Range]) -> Vec<u64> {
2221 self.get_approximate_sizes_cfopt(None::<&ColumnFamily>, ranges)
2222 }
2223
2224 pub fn get_approximate_sizes_cf(
2225 &self,
2226 cf: &impl AsColumnFamilyRef,
2227 ranges: &[Range],
2228 ) -> Vec<u64> {
2229 self.get_approximate_sizes_cfopt(Some(cf), ranges)
2230 }
2231
2232 fn get_approximate_sizes_cfopt(
2233 &self,
2234 cf: Option<&impl AsColumnFamilyRef>,
2235 ranges: &[Range],
2236 ) -> Vec<u64> {
2237 let start_keys: Vec<*const c_char> = ranges
2238 .iter()
2239 .map(|x| x.start_key.as_ptr() as *const c_char)
2240 .collect();
2241 let start_key_lens: Vec<_> = ranges.iter().map(|x| x.start_key.len()).collect();
2242 let end_keys: Vec<*const c_char> = ranges
2243 .iter()
2244 .map(|x| x.end_key.as_ptr() as *const c_char)
2245 .collect();
2246 let end_key_lens: Vec<_> = ranges.iter().map(|x| x.end_key.len()).collect();
2247 let mut sizes: Vec<u64> = vec![0; ranges.len()];
2248 let (n, start_key_ptr, start_key_len_ptr, end_key_ptr, end_key_len_ptr, size_ptr) = (
2249 ranges.len() as i32,
2250 start_keys.as_ptr(),
2251 start_key_lens.as_ptr(),
2252 end_keys.as_ptr(),
2253 end_key_lens.as_ptr(),
2254 sizes.as_mut_ptr(),
2255 );
2256 let mut err: *mut c_char = ptr::null_mut();
2257 match cf {
2258 None => unsafe {
2259 ffi::rocksdb_approximate_sizes(
2260 self.inner.inner(),
2261 n,
2262 start_key_ptr,
2263 start_key_len_ptr,
2264 end_key_ptr,
2265 end_key_len_ptr,
2266 size_ptr,
2267 &raw mut err,
2268 );
2269 },
2270 Some(cf) => unsafe {
2271 ffi::rocksdb_approximate_sizes_cf(
2272 self.inner.inner(),
2273 cf.inner(),
2274 n,
2275 start_key_ptr,
2276 start_key_len_ptr,
2277 end_key_ptr,
2278 end_key_len_ptr,
2279 size_ptr,
2280 &raw mut err,
2281 );
2282 },
2283 }
2284 sizes
2285 }
2286
2287 pub fn get_updates_since(&self, seq_number: u64) -> Result<DBWALIterator, Error> {
2298 unsafe {
2299 let opts: *const ffi::rocksdb_wal_readoptions_t = ptr::null();
2303 let iter = ffi_try!(ffi::rocksdb_get_updates_since(
2304 self.inner.inner(),
2305 seq_number,
2306 opts
2307 ));
2308 Ok(DBWALIterator {
2309 inner: iter,
2310 start_seq_number: seq_number,
2311 })
2312 }
2313 }
2314
2315 pub fn try_catch_up_with_primary(&self) -> Result<(), Error> {
2318 unsafe {
2319 ffi_try!(ffi::rocksdb_try_catch_up_with_primary(self.inner.inner()));
2320 }
2321 Ok(())
2322 }
2323
2324 pub fn ingest_external_file<P: AsRef<Path>>(&self, paths: Vec<P>) -> Result<(), Error> {
2326 let opts = IngestExternalFileOptions::default();
2327 self.ingest_external_file_opts(&opts, paths)
2328 }
2329
2330 pub fn ingest_external_file_opts<P: AsRef<Path>>(
2332 &self,
2333 opts: &IngestExternalFileOptions,
2334 paths: Vec<P>,
2335 ) -> Result<(), Error> {
2336 let paths_v: Vec<CString> = paths.iter().map(to_cpath).collect::<Result<Vec<_>, _>>()?;
2337 let cpaths: Vec<_> = paths_v.iter().map(|path| path.as_ptr()).collect();
2338
2339 self.ingest_external_file_raw(opts, &paths_v, &cpaths)
2340 }
2341
2342 pub fn ingest_external_file_cf<P: AsRef<Path>>(
2345 &self,
2346 cf: &impl AsColumnFamilyRef,
2347 paths: Vec<P>,
2348 ) -> Result<(), Error> {
2349 let opts = IngestExternalFileOptions::default();
2350 self.ingest_external_file_cf_opts(cf, &opts, paths)
2351 }
2352
2353 pub fn ingest_external_file_cf_opts<P: AsRef<Path>>(
2355 &self,
2356 cf: &impl AsColumnFamilyRef,
2357 opts: &IngestExternalFileOptions,
2358 paths: Vec<P>,
2359 ) -> Result<(), Error> {
2360 let paths_v: Vec<CString> = paths.iter().map(to_cpath).collect::<Result<Vec<_>, _>>()?;
2361 let cpaths: Vec<_> = paths_v.iter().map(|path| path.as_ptr()).collect();
2362
2363 self.ingest_external_file_raw_cf(cf, opts, &paths_v, &cpaths)
2364 }
2365
2366 fn ingest_external_file_raw(
2367 &self,
2368 opts: &IngestExternalFileOptions,
2369 paths_v: &[CString],
2370 cpaths: &[*const c_char],
2371 ) -> Result<(), Error> {
2372 unsafe {
2373 ffi_try!(ffi::rocksdb_ingest_external_file(
2374 self.inner.inner(),
2375 cpaths.as_ptr(),
2376 paths_v.len(),
2377 opts.inner.cast_const()
2378 ));
2379 Ok(())
2380 }
2381 }
2382
2383 fn ingest_external_file_raw_cf(
2384 &self,
2385 cf: &impl AsColumnFamilyRef,
2386 opts: &IngestExternalFileOptions,
2387 paths_v: &[CString],
2388 cpaths: &[*const c_char],
2389 ) -> Result<(), Error> {
2390 unsafe {
2391 ffi_try!(ffi::rocksdb_ingest_external_file_cf(
2392 self.inner.inner(),
2393 cf.inner(),
2394 cpaths.as_ptr(),
2395 paths_v.len(),
2396 opts.inner.cast_const()
2397 ));
2398 Ok(())
2399 }
2400 }
2401
2402 pub fn get_column_family_metadata(&self) -> ColumnFamilyMetaData {
2404 unsafe {
2405 let ptr = ffi::rocksdb_get_column_family_metadata(self.inner.inner());
2406
2407 let metadata = ColumnFamilyMetaData {
2408 size: ffi::rocksdb_column_family_metadata_get_size(ptr),
2409 name: from_cstr_and_free(ffi::rocksdb_column_family_metadata_get_name(ptr)),
2410 file_count: ffi::rocksdb_column_family_metadata_get_file_count(ptr),
2411 };
2412
2413 ffi::rocksdb_column_family_metadata_destroy(ptr);
2415
2416 metadata
2418 }
2419 }
2420
2421 pub fn get_column_family_metadata_cf(
2423 &self,
2424 cf: &impl AsColumnFamilyRef,
2425 ) -> ColumnFamilyMetaData {
2426 unsafe {
2427 let ptr = ffi::rocksdb_get_column_family_metadata_cf(self.inner.inner(), cf.inner());
2428
2429 let metadata = ColumnFamilyMetaData {
2430 size: ffi::rocksdb_column_family_metadata_get_size(ptr),
2431 name: from_cstr_and_free(ffi::rocksdb_column_family_metadata_get_name(ptr)),
2432 file_count: ffi::rocksdb_column_family_metadata_get_file_count(ptr),
2433 };
2434
2435 ffi::rocksdb_column_family_metadata_destroy(ptr);
2437
2438 metadata
2440 }
2441 }
2442
2443 pub fn live_files(&self) -> Result<Vec<LiveFile>, Error> {
2446 unsafe {
2447 let files = ffi::rocksdb_livefiles(self.inner.inner());
2448 if files.is_null() {
2449 Err(Error::new("Could not get live files".to_owned()))
2450 } else {
2451 let n = ffi::rocksdb_livefiles_count(files);
2452
2453 let mut livefiles = Vec::with_capacity(n as usize);
2454 let mut key_size: usize = 0;
2455
2456 for i in 0..n {
2457 let column_family_name =
2459 from_cstr_without_free(ffi::rocksdb_livefiles_column_family_name(files, i));
2460 let name = from_cstr_without_free(ffi::rocksdb_livefiles_name(files, i));
2461 let size = ffi::rocksdb_livefiles_size(files, i);
2462 let level = ffi::rocksdb_livefiles_level(files, i);
2463
2464 let smallest_key =
2466 ffi::rocksdb_livefiles_smallestkey(files, i, &raw mut key_size);
2467 let smallest_key = raw_data(smallest_key, key_size);
2468
2469 let largest_key =
2471 ffi::rocksdb_livefiles_largestkey(files, i, &raw mut key_size);
2472 let largest_key = raw_data(largest_key, key_size);
2473
2474 livefiles.push(LiveFile {
2475 column_family_name,
2476 name,
2477 size,
2478 level,
2479 start_key: smallest_key,
2480 end_key: largest_key,
2481 num_entries: ffi::rocksdb_livefiles_entries(files, i),
2482 num_deletions: ffi::rocksdb_livefiles_deletions(files, i),
2483 });
2484 }
2485
2486 ffi::rocksdb_livefiles_destroy(files);
2488
2489 Ok(livefiles)
2491 }
2492 }
2493 }
2494
2495 pub fn delete_file_in_range<K: AsRef<[u8]>>(&self, from: K, to: K) -> Result<(), Error> {
2504 let from = from.as_ref();
2505 let to = to.as_ref();
2506 unsafe {
2507 ffi_try!(ffi::rocksdb_delete_file_in_range(
2508 self.inner.inner(),
2509 from.as_ptr() as *const c_char,
2510 from.len() as size_t,
2511 to.as_ptr() as *const c_char,
2512 to.len() as size_t,
2513 ));
2514 Ok(())
2515 }
2516 }
2517
2518 pub fn delete_file_in_range_cf<K: AsRef<[u8]>>(
2520 &self,
2521 cf: &impl AsColumnFamilyRef,
2522 from: K,
2523 to: K,
2524 ) -> Result<(), Error> {
2525 let from = from.as_ref();
2526 let to = to.as_ref();
2527 unsafe {
2528 ffi_try!(ffi::rocksdb_delete_file_in_range_cf(
2529 self.inner.inner(),
2530 cf.inner(),
2531 from.as_ptr() as *const c_char,
2532 from.len() as size_t,
2533 to.as_ptr() as *const c_char,
2534 to.len() as size_t,
2535 ));
2536 Ok(())
2537 }
2538 }
2539
2540 pub fn cancel_all_background_work(&self, wait: bool) {
2542 unsafe {
2543 ffi::rocksdb_cancel_all_background_work(self.inner.inner(), c_uchar::from(wait));
2544 }
2545 }
2546
2547 fn drop_column_family<C>(
2548 &self,
2549 cf_inner: *mut ffi::rocksdb_column_family_handle_t,
2550 cf: C,
2551 ) -> Result<(), Error> {
2552 unsafe {
2553 ffi_try!(ffi::rocksdb_drop_column_family(
2555 self.inner.inner(),
2556 cf_inner
2557 ));
2558 }
2559 drop(cf);
2562 Ok(())
2563 }
2564
2565 pub fn increase_full_history_ts_low<S: AsRef<[u8]>>(
2570 &self,
2571 cf: &impl AsColumnFamilyRef,
2572 ts: S,
2573 ) -> Result<(), Error> {
2574 let ts = ts.as_ref();
2575 unsafe {
2576 ffi_try!(ffi::rocksdb_increase_full_history_ts_low(
2577 self.inner.inner(),
2578 cf.inner(),
2579 ts.as_ptr() as *const c_char,
2580 ts.len() as size_t,
2581 ));
2582 Ok(())
2583 }
2584 }
2585
2586 pub fn get_full_history_ts_low(&self, cf: &impl AsColumnFamilyRef) -> Result<Vec<u8>, Error> {
2588 unsafe {
2589 let mut ts_lowlen = 0;
2590 let ts = ffi_try!(ffi::rocksdb_get_full_history_ts_low(
2591 self.inner.inner(),
2592 cf.inner(),
2593 &raw mut ts_lowlen,
2594 ));
2595
2596 if ts.is_null() {
2597 Err(Error::new("Could not get full_history_ts_low".to_owned()))
2598 } else {
2599 let mut vec = vec![0; ts_lowlen];
2600 ptr::copy_nonoverlapping(ts.cast::<u8>(), vec.as_mut_ptr(), ts_lowlen);
2601 ffi::rocksdb_free(ts as *mut c_void);
2602 Ok(vec)
2603 }
2604 }
2605 }
2606
2607 pub fn get_db_identity(&self) -> Result<Vec<u8>, Error> {
2609 unsafe {
2610 let mut length: usize = 0;
2611 let identity_ptr = ffi::rocksdb_get_db_identity(self.inner.inner(), &raw mut length);
2612 let identity_vec = raw_data(identity_ptr, length);
2613 ffi::rocksdb_free(identity_ptr as *mut c_void);
2614 identity_vec.ok_or_else(|| Error::new("get_db_identity returned NULL".to_string()))
2617 }
2618 }
2619}
2620
2621impl<I: DBInner> DBCommon<SingleThreaded, I> {
2622 pub fn create_cf<N: AsRef<str>>(&mut self, name: N, opts: &Options) -> Result<(), Error> {
2624 let inner = self.create_inner_cf_handle(name.as_ref(), opts)?;
2625 self.cfs
2626 .cfs
2627 .insert(name.as_ref().to_string(), ColumnFamily { inner });
2628 Ok(())
2629 }
2630
2631 pub fn drop_cf(&mut self, name: &str) -> Result<(), Error> {
2633 if let Some(cf) = self.cfs.cfs.remove(name) {
2634 self.drop_column_family(cf.inner, cf)
2635 } else {
2636 Err(Error::new(format!("Invalid column family: {name}")))
2637 }
2638 }
2639
2640 pub fn cf_handle(&self, name: &str) -> Option<&ColumnFamily> {
2642 self.cfs.cfs.get(name)
2643 }
2644}
2645
2646impl<I: DBInner> DBCommon<MultiThreaded, I> {
2647 pub fn create_cf<N: AsRef<str>>(&self, name: N, opts: &Options) -> Result<(), Error> {
2649 let mut cfs = self.cfs.cfs.write().unwrap();
2652 let inner = self.create_inner_cf_handle(name.as_ref(), opts)?;
2653 cfs.insert(
2654 name.as_ref().to_string(),
2655 Arc::new(UnboundColumnFamily { inner }),
2656 );
2657 Ok(())
2658 }
2659
2660 pub fn drop_cf(&self, name: &str) -> Result<(), Error> {
2663 if let Some(cf) = self.cfs.cfs.write().unwrap().remove(name) {
2664 self.drop_column_family(cf.inner, cf)
2665 } else {
2666 Err(Error::new(format!("Invalid column family: {name}")))
2667 }
2668 }
2669
2670 pub fn cf_handle(&self, name: &str) -> Option<Arc<BoundColumnFamily>> {
2672 self.cfs
2673 .cfs
2674 .read()
2675 .unwrap()
2676 .get(name)
2677 .cloned()
2678 .map(UnboundColumnFamily::bound_column_family)
2679 }
2680}
2681
2682impl<T: ThreadMode, I: DBInner> Drop for DBCommon<T, I> {
2683 fn drop(&mut self) {
2684 self.cfs.drop_all_cfs_internal();
2685 }
2686}
2687
2688impl<T: ThreadMode, I: DBInner> fmt::Debug for DBCommon<T, I> {
2689 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2690 write!(f, "RocksDB {{ path: {} }}", self.path().display())
2691 }
2692}
2693
2694#[derive(Debug, Clone)]
2696pub struct ColumnFamilyMetaData {
2697 pub size: u64,
2700 pub name: String,
2702 pub file_count: usize,
2704}
2705
2706#[derive(Debug, Clone)]
2708pub struct LiveFile {
2709 pub column_family_name: String,
2711 pub name: String,
2713 pub size: usize,
2715 pub level: i32,
2717 pub start_key: Option<Vec<u8>>,
2719 pub end_key: Option<Vec<u8>>,
2721 pub num_entries: u64,
2723 pub num_deletions: u64,
2725}
2726
2727fn convert_options(opts: &[(&str, &str)]) -> Result<Vec<(CString, CString)>, Error> {
2728 opts.iter()
2729 .map(|(name, value)| {
2730 let cname = match CString::new(name.as_bytes()) {
2731 Ok(cname) => cname,
2732 Err(e) => return Err(Error::new(format!("Invalid option name `{e}`"))),
2733 };
2734 let cvalue = match CString::new(value.as_bytes()) {
2735 Ok(cvalue) => cvalue,
2736 Err(e) => return Err(Error::new(format!("Invalid option value: `{e}`"))),
2737 };
2738 Ok((cname, cvalue))
2739 })
2740 .collect()
2741}
2742
2743pub(crate) fn convert_values(
2744 values: Vec<*mut c_char>,
2745 values_sizes: Vec<usize>,
2746 errors: Vec<*mut c_char>,
2747) -> Vec<Result<Option<Vec<u8>>, Error>> {
2748 values
2749 .into_iter()
2750 .zip(values_sizes)
2751 .zip(errors)
2752 .map(|((v, s), e)| {
2753 if e.is_null() {
2754 let value = unsafe { crate::ffi_util::raw_data(v, s) };
2755 unsafe {
2756 ffi::rocksdb_free(v as *mut c_void);
2757 }
2758 Ok(value)
2759 } else {
2760 Err(convert_rocksdb_error(e))
2761 }
2762 })
2763 .collect()
2764}