1use crate::{
17 column_family::AsColumnFamilyRef,
18 column_family::BoundColumnFamily,
19 column_family::UnboundColumnFamily,
20 db_options::OptionsMustOutliveDB,
21 ffi,
22 ffi_util::{from_cstr, opt_bytes_to_ptr, raw_data, to_cpath, CStrLike},
23 ColumnFamily, ColumnFamilyDescriptor, CompactOptions, DBIteratorWithThreadMode,
24 DBPinnableSlice, DBRawIteratorWithThreadMode, DBWALIterator, Direction, Error, FlushOptions,
25 IngestExternalFileOptions, IteratorMode, Options, ReadOptions, SnapshotWithThreadMode,
26 WaitForCompactOptions, WriteBatch, WriteOptions, DEFAULT_COLUMN_FAMILY_NAME,
27};
28
29use crate::column_family::ColumnFamilyTtl;
30use crate::ffi_util::CSlice;
31use libc::{self, c_char, c_int, c_uchar, c_void, size_t};
32use std::collections::BTreeMap;
33use std::ffi::{CStr, CString};
34use std::fmt;
35use std::fs;
36use std::iter;
37use std::path::Path;
38use std::path::PathBuf;
39use std::ptr;
40use std::slice;
41use std::str;
42use std::sync::Arc;
43use std::sync::RwLock;
44use std::time::Duration;
45
46pub trait ThreadMode {
57 fn new_cf_map_internal(
59 cf_map: BTreeMap<String, *mut ffi::rocksdb_column_family_handle_t>,
60 ) -> Self;
61 fn drop_all_cfs_internal(&mut self);
63}
64
65pub struct SingleThreaded {
72 pub(crate) cfs: BTreeMap<String, ColumnFamily>,
73}
74
75pub struct MultiThreaded {
81 pub(crate) cfs: RwLock<BTreeMap<String, Arc<UnboundColumnFamily>>>,
82}
83
84impl ThreadMode for SingleThreaded {
85 fn new_cf_map_internal(
86 cfs: BTreeMap<String, *mut ffi::rocksdb_column_family_handle_t>,
87 ) -> Self {
88 Self {
89 cfs: cfs
90 .into_iter()
91 .map(|(n, c)| (n, ColumnFamily { inner: c }))
92 .collect(),
93 }
94 }
95
96 fn drop_all_cfs_internal(&mut self) {
97 self.cfs.clear();
99 }
100}
101
102impl ThreadMode for MultiThreaded {
103 fn new_cf_map_internal(
104 cfs: BTreeMap<String, *mut ffi::rocksdb_column_family_handle_t>,
105 ) -> Self {
106 Self {
107 cfs: RwLock::new(
108 cfs.into_iter()
109 .map(|(n, c)| (n, Arc::new(UnboundColumnFamily { inner: c })))
110 .collect(),
111 ),
112 }
113 }
114
115 fn drop_all_cfs_internal(&mut self) {
116 self.cfs.write().unwrap().clear();
118 }
119}
120
121pub trait DBInner {
123 fn inner(&self) -> *mut ffi::rocksdb_t;
124}
125
126pub struct DBCommon<T: ThreadMode, D: DBInner> {
131 pub(crate) inner: D,
132 cfs: T, path: PathBuf,
134 _outlive: Vec<OptionsMustOutliveDB>,
135}
136
137pub trait DBAccess {
140 unsafe fn create_snapshot(&self) -> *const ffi::rocksdb_snapshot_t;
141
142 unsafe fn release_snapshot(&self, snapshot: *const ffi::rocksdb_snapshot_t);
143
144 unsafe fn create_iterator(&self, readopts: &ReadOptions) -> *mut ffi::rocksdb_iterator_t;
145
146 unsafe fn create_iterator_cf(
147 &self,
148 cf_handle: *mut ffi::rocksdb_column_family_handle_t,
149 readopts: &ReadOptions,
150 ) -> *mut ffi::rocksdb_iterator_t;
151
152 fn get_opt<K: AsRef<[u8]>>(
153 &self,
154 key: K,
155 readopts: &ReadOptions,
156 ) -> Result<Option<Vec<u8>>, Error>;
157
158 fn get_cf_opt<K: AsRef<[u8]>>(
159 &self,
160 cf: &impl AsColumnFamilyRef,
161 key: K,
162 readopts: &ReadOptions,
163 ) -> Result<Option<Vec<u8>>, Error>;
164
165 fn get_pinned_opt<K: AsRef<[u8]>>(
166 &self,
167 key: K,
168 readopts: &ReadOptions,
169 ) -> Result<Option<DBPinnableSlice>, Error>;
170
171 fn get_pinned_cf_opt<K: AsRef<[u8]>>(
172 &self,
173 cf: &impl AsColumnFamilyRef,
174 key: K,
175 readopts: &ReadOptions,
176 ) -> Result<Option<DBPinnableSlice>, Error>;
177
178 fn multi_get_opt<K, I>(
179 &self,
180 keys: I,
181 readopts: &ReadOptions,
182 ) -> Vec<Result<Option<Vec<u8>>, Error>>
183 where
184 K: AsRef<[u8]>,
185 I: IntoIterator<Item = K>;
186
187 fn multi_get_cf_opt<'b, K, I, W>(
188 &self,
189 keys_cf: I,
190 readopts: &ReadOptions,
191 ) -> Vec<Result<Option<Vec<u8>>, Error>>
192 where
193 K: AsRef<[u8]>,
194 I: IntoIterator<Item = (&'b W, K)>,
195 W: AsColumnFamilyRef + 'b;
196}
197
198impl<T: ThreadMode, D: DBInner> DBAccess for DBCommon<T, D> {
199 unsafe fn create_snapshot(&self) -> *const ffi::rocksdb_snapshot_t {
200 ffi::rocksdb_create_snapshot(self.inner.inner())
201 }
202
203 unsafe fn release_snapshot(&self, snapshot: *const ffi::rocksdb_snapshot_t) {
204 ffi::rocksdb_release_snapshot(self.inner.inner(), snapshot);
205 }
206
207 unsafe fn create_iterator(&self, readopts: &ReadOptions) -> *mut ffi::rocksdb_iterator_t {
208 ffi::rocksdb_create_iterator(self.inner.inner(), readopts.inner)
209 }
210
211 unsafe fn create_iterator_cf(
212 &self,
213 cf_handle: *mut ffi::rocksdb_column_family_handle_t,
214 readopts: &ReadOptions,
215 ) -> *mut ffi::rocksdb_iterator_t {
216 ffi::rocksdb_create_iterator_cf(self.inner.inner(), readopts.inner, cf_handle)
217 }
218
219 fn get_opt<K: AsRef<[u8]>>(
220 &self,
221 key: K,
222 readopts: &ReadOptions,
223 ) -> Result<Option<Vec<u8>>, Error> {
224 self.get_opt(key, readopts)
225 }
226
227 fn get_cf_opt<K: AsRef<[u8]>>(
228 &self,
229 cf: &impl AsColumnFamilyRef,
230 key: K,
231 readopts: &ReadOptions,
232 ) -> Result<Option<Vec<u8>>, Error> {
233 self.get_cf_opt(cf, key, readopts)
234 }
235
236 fn get_pinned_opt<K: AsRef<[u8]>>(
237 &self,
238 key: K,
239 readopts: &ReadOptions,
240 ) -> Result<Option<DBPinnableSlice>, Error> {
241 self.get_pinned_opt(key, readopts)
242 }
243
244 fn get_pinned_cf_opt<K: AsRef<[u8]>>(
245 &self,
246 cf: &impl AsColumnFamilyRef,
247 key: K,
248 readopts: &ReadOptions,
249 ) -> Result<Option<DBPinnableSlice>, Error> {
250 self.get_pinned_cf_opt(cf, key, readopts)
251 }
252
253 fn multi_get_opt<K, Iter>(
254 &self,
255 keys: Iter,
256 readopts: &ReadOptions,
257 ) -> Vec<Result<Option<Vec<u8>>, Error>>
258 where
259 K: AsRef<[u8]>,
260 Iter: IntoIterator<Item = K>,
261 {
262 self.multi_get_opt(keys, readopts)
263 }
264
265 fn multi_get_cf_opt<'b, K, Iter, W>(
266 &self,
267 keys_cf: Iter,
268 readopts: &ReadOptions,
269 ) -> Vec<Result<Option<Vec<u8>>, Error>>
270 where
271 K: AsRef<[u8]>,
272 Iter: IntoIterator<Item = (&'b W, K)>,
273 W: AsColumnFamilyRef + 'b,
274 {
275 self.multi_get_cf_opt(keys_cf, readopts)
276 }
277}
278
279pub struct DBWithThreadModeInner {
280 inner: *mut ffi::rocksdb_t,
281}
282
283impl DBInner for DBWithThreadModeInner {
284 fn inner(&self) -> *mut ffi::rocksdb_t {
285 self.inner
286 }
287}
288
289impl Drop for DBWithThreadModeInner {
290 fn drop(&mut self) {
291 unsafe {
292 ffi::rocksdb_close(self.inner);
293 }
294 }
295}
296
297pub type DBWithThreadMode<T> = DBCommon<T, DBWithThreadModeInner>;
302
303#[cfg(not(feature = "multi-threaded-cf"))]
326pub type DB = DBWithThreadMode<SingleThreaded>;
327
328#[cfg(feature = "multi-threaded-cf")]
329pub type DB = DBWithThreadMode<MultiThreaded>;
330
331unsafe impl<T: ThreadMode + Send, I: DBInner> Send for DBCommon<T, I> {}
335
336unsafe impl<T: ThreadMode, I: DBInner> Sync for DBCommon<T, I> {}
339
340enum AccessType<'a> {
342 ReadWrite,
343 ReadOnly { error_if_log_file_exist: bool },
344 Secondary { secondary_path: &'a Path },
345 WithTTL { ttl: Duration },
346}
347
348impl<T: ThreadMode> DBWithThreadMode<T> {
350 pub fn open_default<P: AsRef<Path>>(path: P) -> Result<Self, Error> {
352 let mut opts = Options::default();
353 opts.create_if_missing(true);
354 Self::open(&opts, path)
355 }
356
357 pub fn open<P: AsRef<Path>>(opts: &Options, path: P) -> Result<Self, Error> {
359 Self::open_cf(opts, path, None::<&str>)
360 }
361
362 pub fn open_for_read_only<P: AsRef<Path>>(
364 opts: &Options,
365 path: P,
366 error_if_log_file_exist: bool,
367 ) -> Result<Self, Error> {
368 Self::open_cf_for_read_only(opts, path, None::<&str>, error_if_log_file_exist)
369 }
370
371 pub fn open_as_secondary<P: AsRef<Path>>(
373 opts: &Options,
374 primary_path: P,
375 secondary_path: P,
376 ) -> Result<Self, Error> {
377 Self::open_cf_as_secondary(opts, primary_path, secondary_path, None::<&str>)
378 }
379
380 pub fn open_with_ttl<P: AsRef<Path>>(
385 opts: &Options,
386 path: P,
387 ttl: Duration,
388 ) -> Result<Self, Error> {
389 Self::open_cf_descriptors_with_ttl(opts, path, std::iter::empty(), ttl)
390 }
391
392 pub fn open_cf_with_ttl<P, I, N>(
396 opts: &Options,
397 path: P,
398 cfs: I,
399 ttl: Duration,
400 ) -> Result<Self, Error>
401 where
402 P: AsRef<Path>,
403 I: IntoIterator<Item = N>,
404 N: AsRef<str>,
405 {
406 let cfs = cfs
407 .into_iter()
408 .map(|name| ColumnFamilyDescriptor::new(name.as_ref(), Options::default()));
409
410 Self::open_cf_descriptors_with_ttl(opts, path, cfs, ttl)
411 }
412
413 pub fn open_cf_descriptors_with_ttl<P, I>(
427 opts: &Options,
428 path: P,
429 cfs: I,
430 ttl: Duration,
431 ) -> Result<Self, Error>
432 where
433 P: AsRef<Path>,
434 I: IntoIterator<Item = ColumnFamilyDescriptor>,
435 {
436 Self::open_cf_descriptors_internal(opts, path, cfs, &AccessType::WithTTL { ttl })
437 }
438
439 pub fn open_cf<P, I, N>(opts: &Options, path: P, cfs: I) -> Result<Self, Error>
443 where
444 P: AsRef<Path>,
445 I: IntoIterator<Item = N>,
446 N: AsRef<str>,
447 {
448 let cfs = cfs
449 .into_iter()
450 .map(|name| ColumnFamilyDescriptor::new(name.as_ref(), Options::default()));
451
452 Self::open_cf_descriptors_internal(opts, path, cfs, &AccessType::ReadWrite)
453 }
454
455 pub fn open_cf_with_opts<P, I, N>(opts: &Options, path: P, cfs: I) -> Result<Self, Error>
459 where
460 P: AsRef<Path>,
461 I: IntoIterator<Item = (N, Options)>,
462 N: AsRef<str>,
463 {
464 let cfs = cfs
465 .into_iter()
466 .map(|(name, opts)| ColumnFamilyDescriptor::new(name.as_ref(), opts));
467
468 Self::open_cf_descriptors(opts, path, cfs)
469 }
470
471 pub fn open_cf_for_read_only<P, I, N>(
475 opts: &Options,
476 path: P,
477 cfs: I,
478 error_if_log_file_exist: bool,
479 ) -> Result<Self, Error>
480 where
481 P: AsRef<Path>,
482 I: IntoIterator<Item = N>,
483 N: AsRef<str>,
484 {
485 let cfs = cfs
486 .into_iter()
487 .map(|name| ColumnFamilyDescriptor::new(name.as_ref(), Options::default()));
488
489 Self::open_cf_descriptors_internal(
490 opts,
491 path,
492 cfs,
493 &AccessType::ReadOnly {
494 error_if_log_file_exist,
495 },
496 )
497 }
498
499 pub fn open_cf_with_opts_for_read_only<P, I, N>(
503 db_opts: &Options,
504 path: P,
505 cfs: I,
506 error_if_log_file_exist: bool,
507 ) -> Result<Self, Error>
508 where
509 P: AsRef<Path>,
510 I: IntoIterator<Item = (N, Options)>,
511 N: AsRef<str>,
512 {
513 let cfs = cfs
514 .into_iter()
515 .map(|(name, cf_opts)| ColumnFamilyDescriptor::new(name.as_ref(), cf_opts));
516
517 Self::open_cf_descriptors_internal(
518 db_opts,
519 path,
520 cfs,
521 &AccessType::ReadOnly {
522 error_if_log_file_exist,
523 },
524 )
525 }
526
527 pub fn open_cf_descriptors_read_only<P, I>(
532 opts: &Options,
533 path: P,
534 cfs: I,
535 error_if_log_file_exist: bool,
536 ) -> Result<Self, Error>
537 where
538 P: AsRef<Path>,
539 I: IntoIterator<Item = ColumnFamilyDescriptor>,
540 {
541 Self::open_cf_descriptors_internal(
542 opts,
543 path,
544 cfs,
545 &AccessType::ReadOnly {
546 error_if_log_file_exist,
547 },
548 )
549 }
550
551 pub fn open_cf_as_secondary<P, I, N>(
555 opts: &Options,
556 primary_path: P,
557 secondary_path: P,
558 cfs: I,
559 ) -> Result<Self, Error>
560 where
561 P: AsRef<Path>,
562 I: IntoIterator<Item = N>,
563 N: AsRef<str>,
564 {
565 let cfs = cfs
566 .into_iter()
567 .map(|name| ColumnFamilyDescriptor::new(name.as_ref(), Options::default()));
568
569 Self::open_cf_descriptors_internal(
570 opts,
571 primary_path,
572 cfs,
573 &AccessType::Secondary {
574 secondary_path: secondary_path.as_ref(),
575 },
576 )
577 }
578
579 pub fn open_cf_descriptors_as_secondary<P, I>(
584 opts: &Options,
585 path: P,
586 secondary_path: P,
587 cfs: I,
588 ) -> Result<Self, Error>
589 where
590 P: AsRef<Path>,
591 I: IntoIterator<Item = ColumnFamilyDescriptor>,
592 {
593 Self::open_cf_descriptors_internal(
594 opts,
595 path,
596 cfs,
597 &AccessType::Secondary {
598 secondary_path: secondary_path.as_ref(),
599 },
600 )
601 }
602
603 pub fn open_cf_descriptors<P, I>(opts: &Options, path: P, cfs: I) -> Result<Self, Error>
607 where
608 P: AsRef<Path>,
609 I: IntoIterator<Item = ColumnFamilyDescriptor>,
610 {
611 Self::open_cf_descriptors_internal(opts, path, cfs, &AccessType::ReadWrite)
612 }
613
614 fn open_cf_descriptors_internal<P, I>(
616 opts: &Options,
617 path: P,
618 cfs: I,
619 access_type: &AccessType,
620 ) -> Result<Self, Error>
621 where
622 P: AsRef<Path>,
623 I: IntoIterator<Item = ColumnFamilyDescriptor>,
624 {
625 let cfs: Vec<_> = cfs.into_iter().collect();
626 let outlive = iter::once(opts.outlive.clone())
627 .chain(cfs.iter().map(|cf| cf.options.outlive.clone()))
628 .collect();
629
630 let cpath = to_cpath(&path)?;
631
632 if let Err(e) = fs::create_dir_all(&path) {
633 return Err(Error::new(format!(
634 "Failed to create RocksDB directory: `{e:?}`."
635 )));
636 }
637
638 let db: *mut ffi::rocksdb_t;
639 let mut cf_map = BTreeMap::new();
640
641 if cfs.is_empty() {
642 db = Self::open_raw(opts, &cpath, access_type)?;
643 } else {
644 let mut cfs_v = cfs;
645 if !cfs_v.iter().any(|cf| cf.name == DEFAULT_COLUMN_FAMILY_NAME) {
647 cfs_v.push(ColumnFamilyDescriptor {
648 name: String::from(DEFAULT_COLUMN_FAMILY_NAME),
649 options: Options::default(),
650 ttl: ColumnFamilyTtl::SameAsDb,
651 });
652 }
653 let c_cfs: Vec<CString> = cfs_v
656 .iter()
657 .map(|cf| CString::new(cf.name.as_bytes()).unwrap())
658 .collect();
659
660 let cfnames: Vec<_> = c_cfs.iter().map(|cf| cf.as_ptr()).collect();
661
662 let mut cfhandles: Vec<_> = cfs_v.iter().map(|_| ptr::null_mut()).collect();
664
665 let cfopts: Vec<_> = cfs_v
666 .iter()
667 .map(|cf| cf.options.inner.cast_const())
668 .collect();
669
670 db = Self::open_cf_raw(
671 opts,
672 &cpath,
673 &cfs_v,
674 &cfnames,
675 &cfopts,
676 &mut cfhandles,
677 access_type,
678 )?;
679 for handle in &cfhandles {
680 if handle.is_null() {
681 return Err(Error::new(
682 "Received null column family handle from DB.".to_owned(),
683 ));
684 }
685 }
686
687 for (cf_desc, inner) in cfs_v.iter().zip(cfhandles) {
688 cf_map.insert(cf_desc.name.clone(), inner);
689 }
690 }
691
692 if db.is_null() {
693 return Err(Error::new("Could not initialize database.".to_owned()));
694 }
695
696 Ok(Self {
697 inner: DBWithThreadModeInner { inner: db },
698 path: path.as_ref().to_path_buf(),
699 cfs: T::new_cf_map_internal(cf_map),
700 _outlive: outlive,
701 })
702 }
703
704 fn open_raw(
705 opts: &Options,
706 cpath: &CString,
707 access_type: &AccessType,
708 ) -> Result<*mut ffi::rocksdb_t, Error> {
709 let db = unsafe {
710 match *access_type {
711 AccessType::ReadOnly {
712 error_if_log_file_exist,
713 } => ffi_try!(ffi::rocksdb_open_for_read_only(
714 opts.inner,
715 cpath.as_ptr(),
716 c_uchar::from(error_if_log_file_exist),
717 )),
718 AccessType::ReadWrite => {
719 ffi_try!(ffi::rocksdb_open(opts.inner, cpath.as_ptr()))
720 }
721 AccessType::Secondary { secondary_path } => {
722 ffi_try!(ffi::rocksdb_open_as_secondary(
723 opts.inner,
724 cpath.as_ptr(),
725 to_cpath(secondary_path)?.as_ptr(),
726 ))
727 }
728 AccessType::WithTTL { ttl } => ffi_try!(ffi::rocksdb_open_with_ttl(
729 opts.inner,
730 cpath.as_ptr(),
731 ttl.as_secs() as c_int,
732 )),
733 }
734 };
735 Ok(db)
736 }
737
738 #[allow(clippy::pedantic)]
739 fn open_cf_raw(
740 opts: &Options,
741 cpath: &CString,
742 cfs_v: &[ColumnFamilyDescriptor],
743 cfnames: &[*const c_char],
744 cfopts: &[*const ffi::rocksdb_options_t],
745 cfhandles: &mut [*mut ffi::rocksdb_column_family_handle_t],
746 access_type: &AccessType,
747 ) -> Result<*mut ffi::rocksdb_t, Error> {
748 let db = unsafe {
749 match *access_type {
750 AccessType::ReadOnly {
751 error_if_log_file_exist,
752 } => ffi_try!(ffi::rocksdb_open_for_read_only_column_families(
753 opts.inner,
754 cpath.as_ptr(),
755 cfs_v.len() as c_int,
756 cfnames.as_ptr(),
757 cfopts.as_ptr(),
758 cfhandles.as_mut_ptr(),
759 c_uchar::from(error_if_log_file_exist),
760 )),
761 AccessType::ReadWrite => ffi_try!(ffi::rocksdb_open_column_families(
762 opts.inner,
763 cpath.as_ptr(),
764 cfs_v.len() as c_int,
765 cfnames.as_ptr(),
766 cfopts.as_ptr(),
767 cfhandles.as_mut_ptr(),
768 )),
769 AccessType::Secondary { secondary_path } => {
770 ffi_try!(ffi::rocksdb_open_as_secondary_column_families(
771 opts.inner,
772 cpath.as_ptr(),
773 to_cpath(secondary_path)?.as_ptr(),
774 cfs_v.len() as c_int,
775 cfnames.as_ptr(),
776 cfopts.as_ptr(),
777 cfhandles.as_mut_ptr(),
778 ))
779 }
780 AccessType::WithTTL { ttl } => {
781 let ttls: Vec<_> = cfs_v
782 .iter()
783 .map(|cf| match cf.ttl {
784 ColumnFamilyTtl::Disabled => i32::MAX,
785 ColumnFamilyTtl::Duration(duration) => duration.as_secs() as i32,
786 ColumnFamilyTtl::SameAsDb => ttl.as_secs() as i32,
787 })
788 .collect();
789
790 ffi_try!(ffi::rocksdb_open_column_families_with_ttl(
791 opts.inner,
792 cpath.as_ptr(),
793 cfs_v.len() as c_int,
794 cfnames.as_ptr(),
795 cfopts.as_ptr(),
796 cfhandles.as_mut_ptr(),
797 ttls.as_ptr(),
798 ))
799 }
800 }
801 };
802 Ok(db)
803 }
804
805 pub fn delete_range_cf_opt<K: AsRef<[u8]>>(
807 &self,
808 cf: &impl AsColumnFamilyRef,
809 from: K,
810 to: K,
811 writeopts: &WriteOptions,
812 ) -> Result<(), Error> {
813 let from = from.as_ref();
814 let to = to.as_ref();
815
816 unsafe {
817 ffi_try!(ffi::rocksdb_delete_range_cf(
818 self.inner.inner(),
819 writeopts.inner,
820 cf.inner(),
821 from.as_ptr() as *const c_char,
822 from.len() as size_t,
823 to.as_ptr() as *const c_char,
824 to.len() as size_t,
825 ));
826 Ok(())
827 }
828 }
829
830 pub fn delete_range_cf<K: AsRef<[u8]>>(
832 &self,
833 cf: &impl AsColumnFamilyRef,
834 from: K,
835 to: K,
836 ) -> Result<(), Error> {
837 self.delete_range_cf_opt(cf, from, to, &WriteOptions::default())
838 }
839
840 pub fn write_opt(&self, batch: WriteBatch, writeopts: &WriteOptions) -> Result<(), Error> {
841 unsafe {
842 ffi_try!(ffi::rocksdb_write(
843 self.inner.inner(),
844 writeopts.inner,
845 batch.inner
846 ));
847 }
848 Ok(())
849 }
850
851 pub fn write(&self, batch: WriteBatch) -> Result<(), Error> {
852 self.write_opt(batch, &WriteOptions::default())
853 }
854
855 pub fn write_without_wal(&self, batch: WriteBatch) -> Result<(), Error> {
856 let mut wo = WriteOptions::new();
857 wo.disable_wal(true);
858 self.write_opt(batch, &wo)
859 }
860}
861
862impl<T: ThreadMode, D: DBInner> DBCommon<T, D> {
864 pub(crate) fn new(inner: D, cfs: T, path: PathBuf, outlive: Vec<OptionsMustOutliveDB>) -> Self {
865 Self {
866 inner,
867 cfs,
868 path,
869 _outlive: outlive,
870 }
871 }
872
873 pub fn list_cf<P: AsRef<Path>>(opts: &Options, path: P) -> Result<Vec<String>, Error> {
874 let cpath = to_cpath(path)?;
875 let mut length = 0;
876
877 unsafe {
878 let ptr = ffi_try!(ffi::rocksdb_list_column_families(
879 opts.inner,
880 cpath.as_ptr(),
881 &mut length,
882 ));
883
884 let vec = slice::from_raw_parts(ptr, length)
885 .iter()
886 .map(|ptr| CStr::from_ptr(*ptr).to_string_lossy().into_owned())
887 .collect();
888 ffi::rocksdb_list_column_families_destroy(ptr, length);
889 Ok(vec)
890 }
891 }
892
893 pub fn destroy<P: AsRef<Path>>(opts: &Options, path: P) -> Result<(), Error> {
894 let cpath = to_cpath(path)?;
895 unsafe {
896 ffi_try!(ffi::rocksdb_destroy_db(opts.inner, cpath.as_ptr()));
897 }
898 Ok(())
899 }
900
901 pub fn repair<P: AsRef<Path>>(opts: &Options, path: P) -> Result<(), Error> {
902 let cpath = to_cpath(path)?;
903 unsafe {
904 ffi_try!(ffi::rocksdb_repair_db(opts.inner, cpath.as_ptr()));
905 }
906 Ok(())
907 }
908
909 pub fn path(&self) -> &Path {
910 self.path.as_path()
911 }
912
913 pub fn flush_wal(&self, sync: bool) -> Result<(), Error> {
916 unsafe {
917 ffi_try!(ffi::rocksdb_flush_wal(
918 self.inner.inner(),
919 c_uchar::from(sync)
920 ));
921 }
922 Ok(())
923 }
924
925 pub fn flush_opt(&self, flushopts: &FlushOptions) -> Result<(), Error> {
927 unsafe {
928 ffi_try!(ffi::rocksdb_flush(self.inner.inner(), flushopts.inner));
929 }
930 Ok(())
931 }
932
933 pub fn flush(&self) -> Result<(), Error> {
935 self.flush_opt(&FlushOptions::default())
936 }
937
938 pub fn flush_cf_opt(
940 &self,
941 cf: &impl AsColumnFamilyRef,
942 flushopts: &FlushOptions,
943 ) -> Result<(), Error> {
944 unsafe {
945 ffi_try!(ffi::rocksdb_flush_cf(
946 self.inner.inner(),
947 flushopts.inner,
948 cf.inner()
949 ));
950 }
951 Ok(())
952 }
953
954 pub fn flush_cfs_opt(
960 &self,
961 cfs: &[&impl AsColumnFamilyRef],
962 opts: &FlushOptions,
963 ) -> Result<(), Error> {
964 let mut cfs = cfs.iter().map(|cf| cf.inner()).collect::<Vec<_>>();
965 unsafe {
966 ffi_try!(ffi::rocksdb_flush_cfs(
967 self.inner.inner(),
968 opts.inner,
969 cfs.as_mut_ptr(),
970 cfs.len() as libc::c_int,
971 ));
972 }
973 Ok(())
974 }
975
976 pub fn flush_cf(&self, cf: &impl AsColumnFamilyRef) -> Result<(), Error> {
979 self.flush_cf_opt(cf, &FlushOptions::default())
980 }
981
982 pub fn get_opt<K: AsRef<[u8]>>(
986 &self,
987 key: K,
988 readopts: &ReadOptions,
989 ) -> Result<Option<Vec<u8>>, Error> {
990 self.get_pinned_opt(key, readopts)
991 .map(|x| x.map(|v| v.as_ref().to_vec()))
992 }
993
994 pub fn get<K: AsRef<[u8]>>(&self, key: K) -> Result<Option<Vec<u8>>, Error> {
998 self.get_opt(key.as_ref(), &ReadOptions::default())
999 }
1000
1001 pub fn get_cf_opt<K: AsRef<[u8]>>(
1005 &self,
1006 cf: &impl AsColumnFamilyRef,
1007 key: K,
1008 readopts: &ReadOptions,
1009 ) -> Result<Option<Vec<u8>>, Error> {
1010 self.get_pinned_cf_opt(cf, key, readopts)
1011 .map(|x| x.map(|v| v.as_ref().to_vec()))
1012 }
1013
1014 pub fn get_cf<K: AsRef<[u8]>>(
1018 &self,
1019 cf: &impl AsColumnFamilyRef,
1020 key: K,
1021 ) -> Result<Option<Vec<u8>>, Error> {
1022 self.get_cf_opt(cf, key.as_ref(), &ReadOptions::default())
1023 }
1024
1025 pub fn get_pinned_opt<K: AsRef<[u8]>>(
1028 &self,
1029 key: K,
1030 readopts: &ReadOptions,
1031 ) -> Result<Option<DBPinnableSlice>, Error> {
1032 if readopts.inner.is_null() {
1033 return Err(Error::new(
1034 "Unable to create RocksDB read options. This is a fairly trivial call, and its \
1035 failure may be indicative of a mis-compiled or mis-loaded RocksDB library."
1036 .to_owned(),
1037 ));
1038 }
1039
1040 let key = key.as_ref();
1041 unsafe {
1042 let val = ffi_try!(ffi::rocksdb_get_pinned(
1043 self.inner.inner(),
1044 readopts.inner,
1045 key.as_ptr() as *const c_char,
1046 key.len() as size_t,
1047 ));
1048 if val.is_null() {
1049 Ok(None)
1050 } else {
1051 Ok(Some(DBPinnableSlice::from_c(val)))
1052 }
1053 }
1054 }
1055
1056 pub fn get_pinned<K: AsRef<[u8]>>(&self, key: K) -> Result<Option<DBPinnableSlice>, Error> {
1060 self.get_pinned_opt(key, &ReadOptions::default())
1061 }
1062
1063 pub fn get_pinned_cf_opt<K: AsRef<[u8]>>(
1067 &self,
1068 cf: &impl AsColumnFamilyRef,
1069 key: K,
1070 readopts: &ReadOptions,
1071 ) -> Result<Option<DBPinnableSlice>, Error> {
1072 if readopts.inner.is_null() {
1073 return Err(Error::new(
1074 "Unable to create RocksDB read options. This is a fairly trivial call, and its \
1075 failure may be indicative of a mis-compiled or mis-loaded RocksDB library."
1076 .to_owned(),
1077 ));
1078 }
1079
1080 let key = key.as_ref();
1081 unsafe {
1082 let val = ffi_try!(ffi::rocksdb_get_pinned_cf(
1083 self.inner.inner(),
1084 readopts.inner,
1085 cf.inner(),
1086 key.as_ptr() as *const c_char,
1087 key.len() as size_t,
1088 ));
1089 if val.is_null() {
1090 Ok(None)
1091 } else {
1092 Ok(Some(DBPinnableSlice::from_c(val)))
1093 }
1094 }
1095 }
1096
1097 pub fn get_pinned_cf<K: AsRef<[u8]>>(
1101 &self,
1102 cf: &impl AsColumnFamilyRef,
1103 key: K,
1104 ) -> Result<Option<DBPinnableSlice>, Error> {
1105 self.get_pinned_cf_opt(cf, key, &ReadOptions::default())
1106 }
1107
1108 pub fn multi_get<K, I>(&self, keys: I) -> Vec<Result<Option<Vec<u8>>, Error>>
1110 where
1111 K: AsRef<[u8]>,
1112 I: IntoIterator<Item = K>,
1113 {
1114 self.multi_get_opt(keys, &ReadOptions::default())
1115 }
1116
1117 pub fn multi_get_opt<K, I>(
1119 &self,
1120 keys: I,
1121 readopts: &ReadOptions,
1122 ) -> Vec<Result<Option<Vec<u8>>, Error>>
1123 where
1124 K: AsRef<[u8]>,
1125 I: IntoIterator<Item = K>,
1126 {
1127 let (keys, keys_sizes): (Vec<Box<[u8]>>, Vec<_>) = keys
1128 .into_iter()
1129 .map(|k| {
1130 let k = k.as_ref();
1131 (Box::from(k), k.len())
1132 })
1133 .unzip();
1134 let ptr_keys: Vec<_> = keys.iter().map(|k| k.as_ptr() as *const c_char).collect();
1135
1136 let mut values = vec![ptr::null_mut(); keys.len()];
1137 let mut values_sizes = vec![0_usize; keys.len()];
1138 let mut errors = vec![ptr::null_mut(); keys.len()];
1139 unsafe {
1140 ffi::rocksdb_multi_get(
1141 self.inner.inner(),
1142 readopts.inner,
1143 ptr_keys.len(),
1144 ptr_keys.as_ptr(),
1145 keys_sizes.as_ptr(),
1146 values.as_mut_ptr(),
1147 values_sizes.as_mut_ptr(),
1148 errors.as_mut_ptr(),
1149 );
1150 }
1151
1152 convert_values(values, values_sizes, errors)
1153 }
1154
1155 pub fn multi_get_cf<'a, 'b: 'a, K, I, W>(
1157 &'a self,
1158 keys: I,
1159 ) -> Vec<Result<Option<Vec<u8>>, Error>>
1160 where
1161 K: AsRef<[u8]>,
1162 I: IntoIterator<Item = (&'b W, K)>,
1163 W: 'b + AsColumnFamilyRef,
1164 {
1165 self.multi_get_cf_opt(keys, &ReadOptions::default())
1166 }
1167
1168 pub fn multi_get_cf_opt<'a, 'b: 'a, K, I, W>(
1170 &'a self,
1171 keys: I,
1172 readopts: &ReadOptions,
1173 ) -> Vec<Result<Option<Vec<u8>>, Error>>
1174 where
1175 K: AsRef<[u8]>,
1176 I: IntoIterator<Item = (&'b W, K)>,
1177 W: 'b + AsColumnFamilyRef,
1178 {
1179 let (cfs_and_keys, keys_sizes): (Vec<(_, Box<[u8]>)>, Vec<_>) = keys
1180 .into_iter()
1181 .map(|(cf, key)| {
1182 let key = key.as_ref();
1183 ((cf, Box::from(key)), key.len())
1184 })
1185 .unzip();
1186 let ptr_keys: Vec<_> = cfs_and_keys
1187 .iter()
1188 .map(|(_, k)| k.as_ptr() as *const c_char)
1189 .collect();
1190 let ptr_cfs: Vec<_> = cfs_and_keys
1191 .iter()
1192 .map(|(c, _)| c.inner().cast_const())
1193 .collect();
1194
1195 let mut values = vec![ptr::null_mut(); ptr_keys.len()];
1196 let mut values_sizes = vec![0_usize; ptr_keys.len()];
1197 let mut errors = vec![ptr::null_mut(); ptr_keys.len()];
1198 unsafe {
1199 ffi::rocksdb_multi_get_cf(
1200 self.inner.inner(),
1201 readopts.inner,
1202 ptr_cfs.as_ptr(),
1203 ptr_keys.len(),
1204 ptr_keys.as_ptr(),
1205 keys_sizes.as_ptr(),
1206 values.as_mut_ptr(),
1207 values_sizes.as_mut_ptr(),
1208 errors.as_mut_ptr(),
1209 );
1210 }
1211
1212 convert_values(values, values_sizes, errors)
1213 }
1214
1215 pub fn batched_multi_get_cf<'a, K, I>(
1219 &self,
1220 cf: &impl AsColumnFamilyRef,
1221 keys: I,
1222 sorted_input: bool,
1223 ) -> Vec<Result<Option<DBPinnableSlice>, Error>>
1224 where
1225 K: AsRef<[u8]> + 'a + ?Sized,
1226 I: IntoIterator<Item = &'a K>,
1227 {
1228 self.batched_multi_get_cf_opt(cf, keys, sorted_input, &ReadOptions::default())
1229 }
1230
1231 pub fn batched_multi_get_cf_opt<'a, K, I>(
1235 &self,
1236 cf: &impl AsColumnFamilyRef,
1237 keys: I,
1238 sorted_input: bool,
1239 readopts: &ReadOptions,
1240 ) -> Vec<Result<Option<DBPinnableSlice>, Error>>
1241 where
1242 K: AsRef<[u8]> + 'a + ?Sized,
1243 I: IntoIterator<Item = &'a K>,
1244 {
1245 let (ptr_keys, keys_sizes): (Vec<_>, Vec<_>) = keys
1246 .into_iter()
1247 .map(|k| {
1248 let k = k.as_ref();
1249 (k.as_ptr() as *const c_char, k.len())
1250 })
1251 .unzip();
1252
1253 let mut pinned_values = vec![ptr::null_mut(); ptr_keys.len()];
1254 let mut errors = vec![ptr::null_mut(); ptr_keys.len()];
1255
1256 unsafe {
1257 ffi::rocksdb_batched_multi_get_cf(
1258 self.inner.inner(),
1259 readopts.inner,
1260 cf.inner(),
1261 ptr_keys.len(),
1262 ptr_keys.as_ptr(),
1263 keys_sizes.as_ptr(),
1264 pinned_values.as_mut_ptr(),
1265 errors.as_mut_ptr(),
1266 sorted_input,
1267 );
1268 pinned_values
1269 .into_iter()
1270 .zip(errors)
1271 .map(|(v, e)| {
1272 if e.is_null() {
1273 if v.is_null() {
1274 Ok(None)
1275 } else {
1276 Ok(Some(DBPinnableSlice::from_c(v)))
1277 }
1278 } else {
1279 Err(Error::new(crate::ffi_util::error_message(e)))
1280 }
1281 })
1282 .collect()
1283 }
1284 }
1285
1286 pub fn key_may_exist<K: AsRef<[u8]>>(&self, key: K) -> bool {
1289 self.key_may_exist_opt(key, &ReadOptions::default())
1290 }
1291
1292 pub fn key_may_exist_opt<K: AsRef<[u8]>>(&self, key: K, readopts: &ReadOptions) -> bool {
1295 let key = key.as_ref();
1296 unsafe {
1297 0 != ffi::rocksdb_key_may_exist(
1298 self.inner.inner(),
1299 readopts.inner,
1300 key.as_ptr() as *const c_char,
1301 key.len() as size_t,
1302 ptr::null_mut(), ptr::null_mut(), ptr::null(), 0, ptr::null_mut(), )
1308 }
1309 }
1310
1311 pub fn key_may_exist_cf<K: AsRef<[u8]>>(&self, cf: &impl AsColumnFamilyRef, key: K) -> bool {
1314 self.key_may_exist_cf_opt(cf, key, &ReadOptions::default())
1315 }
1316
1317 pub fn key_may_exist_cf_opt<K: AsRef<[u8]>>(
1320 &self,
1321 cf: &impl AsColumnFamilyRef,
1322 key: K,
1323 readopts: &ReadOptions,
1324 ) -> bool {
1325 let key = key.as_ref();
1326 0 != unsafe {
1327 ffi::rocksdb_key_may_exist_cf(
1328 self.inner.inner(),
1329 readopts.inner,
1330 cf.inner(),
1331 key.as_ptr() as *const c_char,
1332 key.len() as size_t,
1333 ptr::null_mut(), ptr::null_mut(), ptr::null(), 0, ptr::null_mut(), )
1339 }
1340 }
1341
1342 pub fn key_may_exist_cf_opt_value<K: AsRef<[u8]>>(
1349 &self,
1350 cf: &impl AsColumnFamilyRef,
1351 key: K,
1352 readopts: &ReadOptions,
1353 ) -> (bool, Option<CSlice>) {
1354 let key = key.as_ref();
1355 let mut val: *mut c_char = ptr::null_mut();
1356 let mut val_len: usize = 0;
1357 let mut value_found: c_uchar = 0;
1358 let may_exists = 0
1359 != unsafe {
1360 ffi::rocksdb_key_may_exist_cf(
1361 self.inner.inner(),
1362 readopts.inner,
1363 cf.inner(),
1364 key.as_ptr() as *const c_char,
1365 key.len() as size_t,
1366 &mut val, &mut val_len, ptr::null(), 0, &mut value_found, )
1372 };
1373 if may_exists && value_found != 0 {
1376 (
1377 may_exists,
1378 Some(unsafe { CSlice::from_raw_parts(val, val_len) }),
1379 )
1380 } else {
1381 (may_exists, None)
1382 }
1383 }
1384
1385 fn create_inner_cf_handle(
1386 &self,
1387 name: impl CStrLike,
1388 opts: &Options,
1389 ) -> Result<*mut ffi::rocksdb_column_family_handle_t, Error> {
1390 let cf_name = name.bake().map_err(|err| {
1391 Error::new(format!(
1392 "Failed to convert path to CString when creating cf: {err}"
1393 ))
1394 })?;
1395 Ok(unsafe {
1396 ffi_try!(ffi::rocksdb_create_column_family(
1397 self.inner.inner(),
1398 opts.inner,
1399 cf_name.as_ptr(),
1400 ))
1401 })
1402 }
1403
1404 pub fn iterator<'a: 'b, 'b>(
1405 &'a self,
1406 mode: IteratorMode,
1407 ) -> DBIteratorWithThreadMode<'b, Self> {
1408 let readopts = ReadOptions::default();
1409 self.iterator_opt(mode, readopts)
1410 }
1411
1412 pub fn iterator_opt<'a: 'b, 'b>(
1413 &'a self,
1414 mode: IteratorMode,
1415 readopts: ReadOptions,
1416 ) -> DBIteratorWithThreadMode<'b, Self> {
1417 DBIteratorWithThreadMode::new(self, readopts, mode)
1418 }
1419
1420 pub fn iterator_cf_opt<'a: 'b, 'b>(
1423 &'a self,
1424 cf_handle: &impl AsColumnFamilyRef,
1425 readopts: ReadOptions,
1426 mode: IteratorMode,
1427 ) -> DBIteratorWithThreadMode<'b, Self> {
1428 DBIteratorWithThreadMode::new_cf(self, cf_handle.inner(), readopts, mode)
1429 }
1430
1431 pub fn full_iterator<'a: 'b, 'b>(
1435 &'a self,
1436 mode: IteratorMode,
1437 ) -> DBIteratorWithThreadMode<'b, Self> {
1438 let mut opts = ReadOptions::default();
1439 opts.set_total_order_seek(true);
1440 DBIteratorWithThreadMode::new(self, opts, mode)
1441 }
1442
1443 pub fn prefix_iterator<'a: 'b, 'b, P: AsRef<[u8]>>(
1444 &'a self,
1445 prefix: P,
1446 ) -> DBIteratorWithThreadMode<'b, Self> {
1447 let mut opts = ReadOptions::default();
1448 opts.set_prefix_same_as_start(true);
1449 DBIteratorWithThreadMode::new(
1450 self,
1451 opts,
1452 IteratorMode::From(prefix.as_ref(), Direction::Forward),
1453 )
1454 }
1455
1456 pub fn iterator_cf<'a: 'b, 'b>(
1457 &'a self,
1458 cf_handle: &impl AsColumnFamilyRef,
1459 mode: IteratorMode,
1460 ) -> DBIteratorWithThreadMode<'b, Self> {
1461 let opts = ReadOptions::default();
1462 DBIteratorWithThreadMode::new_cf(self, cf_handle.inner(), opts, mode)
1463 }
1464
1465 pub fn full_iterator_cf<'a: 'b, 'b>(
1466 &'a self,
1467 cf_handle: &impl AsColumnFamilyRef,
1468 mode: IteratorMode,
1469 ) -> DBIteratorWithThreadMode<'b, Self> {
1470 let mut opts = ReadOptions::default();
1471 opts.set_total_order_seek(true);
1472 DBIteratorWithThreadMode::new_cf(self, cf_handle.inner(), opts, mode)
1473 }
1474
1475 pub fn prefix_iterator_cf<'a, P: AsRef<[u8]>>(
1476 &'a self,
1477 cf_handle: &impl AsColumnFamilyRef,
1478 prefix: P,
1479 ) -> DBIteratorWithThreadMode<'a, Self> {
1480 let mut opts = ReadOptions::default();
1481 opts.set_prefix_same_as_start(true);
1482 DBIteratorWithThreadMode::<'a, Self>::new_cf(
1483 self,
1484 cf_handle.inner(),
1485 opts,
1486 IteratorMode::From(prefix.as_ref(), Direction::Forward),
1487 )
1488 }
1489
1490 pub fn raw_iterator<'a: 'b, 'b>(&'a self) -> DBRawIteratorWithThreadMode<'b, Self> {
1492 let opts = ReadOptions::default();
1493 DBRawIteratorWithThreadMode::new(self, opts)
1494 }
1495
1496 pub fn raw_iterator_cf<'a: 'b, 'b>(
1498 &'a self,
1499 cf_handle: &impl AsColumnFamilyRef,
1500 ) -> DBRawIteratorWithThreadMode<'b, Self> {
1501 let opts = ReadOptions::default();
1502 DBRawIteratorWithThreadMode::new_cf(self, cf_handle.inner(), opts)
1503 }
1504
1505 pub fn raw_iterator_opt<'a: 'b, 'b>(
1507 &'a self,
1508 readopts: ReadOptions,
1509 ) -> DBRawIteratorWithThreadMode<'b, Self> {
1510 DBRawIteratorWithThreadMode::new(self, readopts)
1511 }
1512
1513 pub fn raw_iterator_cf_opt<'a: 'b, 'b>(
1515 &'a self,
1516 cf_handle: &impl AsColumnFamilyRef,
1517 readopts: ReadOptions,
1518 ) -> DBRawIteratorWithThreadMode<'b, Self> {
1519 DBRawIteratorWithThreadMode::new_cf(self, cf_handle.inner(), readopts)
1520 }
1521
1522 pub fn snapshot(&self) -> SnapshotWithThreadMode<Self> {
1523 SnapshotWithThreadMode::<Self>::new(self)
1524 }
1525
1526 pub fn put_opt<K, V>(&self, key: K, value: V, writeopts: &WriteOptions) -> Result<(), Error>
1527 where
1528 K: AsRef<[u8]>,
1529 V: AsRef<[u8]>,
1530 {
1531 let key = key.as_ref();
1532 let value = value.as_ref();
1533
1534 unsafe {
1535 ffi_try!(ffi::rocksdb_put(
1536 self.inner.inner(),
1537 writeopts.inner,
1538 key.as_ptr() as *const c_char,
1539 key.len() as size_t,
1540 value.as_ptr() as *const c_char,
1541 value.len() as size_t,
1542 ));
1543 Ok(())
1544 }
1545 }
1546
1547 pub fn put_cf_opt<K, V>(
1548 &self,
1549 cf: &impl AsColumnFamilyRef,
1550 key: K,
1551 value: V,
1552 writeopts: &WriteOptions,
1553 ) -> Result<(), Error>
1554 where
1555 K: AsRef<[u8]>,
1556 V: AsRef<[u8]>,
1557 {
1558 let key = key.as_ref();
1559 let value = value.as_ref();
1560
1561 unsafe {
1562 ffi_try!(ffi::rocksdb_put_cf(
1563 self.inner.inner(),
1564 writeopts.inner,
1565 cf.inner(),
1566 key.as_ptr() as *const c_char,
1567 key.len() as size_t,
1568 value.as_ptr() as *const c_char,
1569 value.len() as size_t,
1570 ));
1571 Ok(())
1572 }
1573 }
1574
1575 pub fn put_with_ts_opt<K, V, S>(
1582 &self,
1583 key: K,
1584 ts: S,
1585 value: V,
1586 writeopts: &WriteOptions,
1587 ) -> Result<(), Error>
1588 where
1589 K: AsRef<[u8]>,
1590 V: AsRef<[u8]>,
1591 S: AsRef<[u8]>,
1592 {
1593 let key = key.as_ref();
1594 let value = value.as_ref();
1595 let ts = ts.as_ref();
1596 unsafe {
1597 ffi_try!(ffi::rocksdb_put_with_ts(
1598 self.inner.inner(),
1599 writeopts.inner,
1600 key.as_ptr() as *const c_char,
1601 key.len() as size_t,
1602 ts.as_ptr() as *const c_char,
1603 ts.len() as size_t,
1604 value.as_ptr() as *const c_char,
1605 value.len() as size_t,
1606 ));
1607 Ok(())
1608 }
1609 }
1610
1611 pub fn put_cf_with_ts_opt<K, V, S>(
1618 &self,
1619 cf: &impl AsColumnFamilyRef,
1620 key: K,
1621 ts: S,
1622 value: V,
1623 writeopts: &WriteOptions,
1624 ) -> Result<(), Error>
1625 where
1626 K: AsRef<[u8]>,
1627 V: AsRef<[u8]>,
1628 S: AsRef<[u8]>,
1629 {
1630 let key = key.as_ref();
1631 let value = value.as_ref();
1632 let ts = ts.as_ref();
1633 unsafe {
1634 ffi_try!(ffi::rocksdb_put_cf_with_ts(
1635 self.inner.inner(),
1636 writeopts.inner,
1637 cf.inner(),
1638 key.as_ptr() as *const c_char,
1639 key.len() as size_t,
1640 ts.as_ptr() as *const c_char,
1641 ts.len() as size_t,
1642 value.as_ptr() as *const c_char,
1643 value.len() as size_t,
1644 ));
1645 Ok(())
1646 }
1647 }
1648
1649 pub fn merge_opt<K, V>(&self, key: K, value: V, writeopts: &WriteOptions) -> Result<(), Error>
1650 where
1651 K: AsRef<[u8]>,
1652 V: AsRef<[u8]>,
1653 {
1654 let key = key.as_ref();
1655 let value = value.as_ref();
1656
1657 unsafe {
1658 ffi_try!(ffi::rocksdb_merge(
1659 self.inner.inner(),
1660 writeopts.inner,
1661 key.as_ptr() as *const c_char,
1662 key.len() as size_t,
1663 value.as_ptr() as *const c_char,
1664 value.len() as size_t,
1665 ));
1666 Ok(())
1667 }
1668 }
1669
1670 pub fn merge_cf_opt<K, V>(
1671 &self,
1672 cf: &impl AsColumnFamilyRef,
1673 key: K,
1674 value: V,
1675 writeopts: &WriteOptions,
1676 ) -> Result<(), Error>
1677 where
1678 K: AsRef<[u8]>,
1679 V: AsRef<[u8]>,
1680 {
1681 let key = key.as_ref();
1682 let value = value.as_ref();
1683
1684 unsafe {
1685 ffi_try!(ffi::rocksdb_merge_cf(
1686 self.inner.inner(),
1687 writeopts.inner,
1688 cf.inner(),
1689 key.as_ptr() as *const c_char,
1690 key.len() as size_t,
1691 value.as_ptr() as *const c_char,
1692 value.len() as size_t,
1693 ));
1694 Ok(())
1695 }
1696 }
1697
1698 pub fn delete_opt<K: AsRef<[u8]>>(
1699 &self,
1700 key: K,
1701 writeopts: &WriteOptions,
1702 ) -> Result<(), Error> {
1703 let key = key.as_ref();
1704
1705 unsafe {
1706 ffi_try!(ffi::rocksdb_delete(
1707 self.inner.inner(),
1708 writeopts.inner,
1709 key.as_ptr() as *const c_char,
1710 key.len() as size_t,
1711 ));
1712 Ok(())
1713 }
1714 }
1715
1716 pub fn delete_cf_opt<K: AsRef<[u8]>>(
1717 &self,
1718 cf: &impl AsColumnFamilyRef,
1719 key: K,
1720 writeopts: &WriteOptions,
1721 ) -> Result<(), Error> {
1722 let key = key.as_ref();
1723
1724 unsafe {
1725 ffi_try!(ffi::rocksdb_delete_cf(
1726 self.inner.inner(),
1727 writeopts.inner,
1728 cf.inner(),
1729 key.as_ptr() as *const c_char,
1730 key.len() as size_t,
1731 ));
1732 Ok(())
1733 }
1734 }
1735
1736 pub fn delete_with_ts_opt<K, S>(
1740 &self,
1741 key: K,
1742 ts: S,
1743 writeopts: &WriteOptions,
1744 ) -> Result<(), Error>
1745 where
1746 K: AsRef<[u8]>,
1747 S: AsRef<[u8]>,
1748 {
1749 let key = key.as_ref();
1750 let ts = ts.as_ref();
1751 unsafe {
1752 ffi_try!(ffi::rocksdb_delete_with_ts(
1753 self.inner.inner(),
1754 writeopts.inner,
1755 key.as_ptr() as *const c_char,
1756 key.len() as size_t,
1757 ts.as_ptr() as *const c_char,
1758 ts.len() as size_t,
1759 ));
1760 Ok(())
1761 }
1762 }
1763
1764 pub fn delete_cf_with_ts_opt<K, S>(
1768 &self,
1769 cf: &impl AsColumnFamilyRef,
1770 key: K,
1771 ts: S,
1772 writeopts: &WriteOptions,
1773 ) -> Result<(), Error>
1774 where
1775 K: AsRef<[u8]>,
1776 S: AsRef<[u8]>,
1777 {
1778 let key = key.as_ref();
1779 let ts = ts.as_ref();
1780 unsafe {
1781 ffi_try!(ffi::rocksdb_delete_cf_with_ts(
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 ts.as_ptr() as *const c_char,
1788 ts.len() as size_t,
1789 ));
1790 Ok(())
1791 }
1792 }
1793
1794 pub fn put<K, V>(&self, key: K, value: V) -> Result<(), Error>
1795 where
1796 K: AsRef<[u8]>,
1797 V: AsRef<[u8]>,
1798 {
1799 self.put_opt(key.as_ref(), value.as_ref(), &WriteOptions::default())
1800 }
1801
1802 pub fn put_cf<K, V>(&self, cf: &impl AsColumnFamilyRef, key: K, value: V) -> Result<(), Error>
1803 where
1804 K: AsRef<[u8]>,
1805 V: AsRef<[u8]>,
1806 {
1807 self.put_cf_opt(cf, key.as_ref(), value.as_ref(), &WriteOptions::default())
1808 }
1809
1810 pub fn put_with_ts<K, V, S>(&self, key: K, ts: S, value: V) -> Result<(), Error>
1817 where
1818 K: AsRef<[u8]>,
1819 V: AsRef<[u8]>,
1820 S: AsRef<[u8]>,
1821 {
1822 self.put_with_ts_opt(
1823 key.as_ref(),
1824 ts.as_ref(),
1825 value.as_ref(),
1826 &WriteOptions::default(),
1827 )
1828 }
1829
1830 pub fn put_cf_with_ts<K, V, S>(
1837 &self,
1838 cf: &impl AsColumnFamilyRef,
1839 key: K,
1840 ts: S,
1841 value: V,
1842 ) -> Result<(), Error>
1843 where
1844 K: AsRef<[u8]>,
1845 V: AsRef<[u8]>,
1846 S: AsRef<[u8]>,
1847 {
1848 self.put_cf_with_ts_opt(
1849 cf,
1850 key.as_ref(),
1851 ts.as_ref(),
1852 value.as_ref(),
1853 &WriteOptions::default(),
1854 )
1855 }
1856
1857 pub fn merge<K, V>(&self, key: K, value: V) -> Result<(), Error>
1858 where
1859 K: AsRef<[u8]>,
1860 V: AsRef<[u8]>,
1861 {
1862 self.merge_opt(key.as_ref(), value.as_ref(), &WriteOptions::default())
1863 }
1864
1865 pub fn merge_cf<K, V>(&self, cf: &impl AsColumnFamilyRef, key: K, value: V) -> Result<(), Error>
1866 where
1867 K: AsRef<[u8]>,
1868 V: AsRef<[u8]>,
1869 {
1870 self.merge_cf_opt(cf, key.as_ref(), value.as_ref(), &WriteOptions::default())
1871 }
1872
1873 pub fn delete<K: AsRef<[u8]>>(&self, key: K) -> Result<(), Error> {
1874 self.delete_opt(key.as_ref(), &WriteOptions::default())
1875 }
1876
1877 pub fn delete_cf<K: AsRef<[u8]>>(
1878 &self,
1879 cf: &impl AsColumnFamilyRef,
1880 key: K,
1881 ) -> Result<(), Error> {
1882 self.delete_cf_opt(cf, key.as_ref(), &WriteOptions::default())
1883 }
1884
1885 pub fn delete_with_ts<K: AsRef<[u8]>, S: AsRef<[u8]>>(
1889 &self,
1890 key: K,
1891 ts: S,
1892 ) -> Result<(), Error> {
1893 self.delete_with_ts_opt(key.as_ref(), ts.as_ref(), &WriteOptions::default())
1894 }
1895
1896 pub fn delete_cf_with_ts<K: AsRef<[u8]>, S: AsRef<[u8]>>(
1900 &self,
1901 cf: &impl AsColumnFamilyRef,
1902 key: K,
1903 ts: S,
1904 ) -> Result<(), Error> {
1905 self.delete_cf_with_ts_opt(cf, key.as_ref(), ts.as_ref(), &WriteOptions::default())
1906 }
1907
1908 pub fn compact_range<S: AsRef<[u8]>, E: AsRef<[u8]>>(&self, start: Option<S>, end: Option<E>) {
1910 unsafe {
1911 let start = start.as_ref().map(AsRef::as_ref);
1912 let end = end.as_ref().map(AsRef::as_ref);
1913
1914 ffi::rocksdb_compact_range(
1915 self.inner.inner(),
1916 opt_bytes_to_ptr(start),
1917 start.map_or(0, <[u8]>::len) as size_t,
1918 opt_bytes_to_ptr(end),
1919 end.map_or(0, <[u8]>::len) as size_t,
1920 );
1921 }
1922 }
1923
1924 pub fn compact_range_opt<S: AsRef<[u8]>, E: AsRef<[u8]>>(
1926 &self,
1927 start: Option<S>,
1928 end: Option<E>,
1929 opts: &CompactOptions,
1930 ) {
1931 unsafe {
1932 let start = start.as_ref().map(AsRef::as_ref);
1933 let end = end.as_ref().map(AsRef::as_ref);
1934
1935 ffi::rocksdb_compact_range_opt(
1936 self.inner.inner(),
1937 opts.inner,
1938 opt_bytes_to_ptr(start),
1939 start.map_or(0, <[u8]>::len) as size_t,
1940 opt_bytes_to_ptr(end),
1941 end.map_or(0, <[u8]>::len) as size_t,
1942 );
1943 }
1944 }
1945
1946 pub fn compact_range_cf<S: AsRef<[u8]>, E: AsRef<[u8]>>(
1949 &self,
1950 cf: &impl AsColumnFamilyRef,
1951 start: Option<S>,
1952 end: Option<E>,
1953 ) {
1954 unsafe {
1955 let start = start.as_ref().map(AsRef::as_ref);
1956 let end = end.as_ref().map(AsRef::as_ref);
1957
1958 ffi::rocksdb_compact_range_cf(
1959 self.inner.inner(),
1960 cf.inner(),
1961 opt_bytes_to_ptr(start),
1962 start.map_or(0, <[u8]>::len) as size_t,
1963 opt_bytes_to_ptr(end),
1964 end.map_or(0, <[u8]>::len) as size_t,
1965 );
1966 }
1967 }
1968
1969 pub fn compact_range_cf_opt<S: AsRef<[u8]>, E: AsRef<[u8]>>(
1971 &self,
1972 cf: &impl AsColumnFamilyRef,
1973 start: Option<S>,
1974 end: Option<E>,
1975 opts: &CompactOptions,
1976 ) {
1977 unsafe {
1978 let start = start.as_ref().map(AsRef::as_ref);
1979 let end = end.as_ref().map(AsRef::as_ref);
1980
1981 ffi::rocksdb_compact_range_cf_opt(
1982 self.inner.inner(),
1983 cf.inner(),
1984 opts.inner,
1985 opt_bytes_to_ptr(start),
1986 start.map_or(0, <[u8]>::len) as size_t,
1987 opt_bytes_to_ptr(end),
1988 end.map_or(0, <[u8]>::len) as size_t,
1989 );
1990 }
1991 }
1992
1993 pub fn wait_for_compact(&self, opts: &WaitForCompactOptions) -> Result<(), Error> {
2002 unsafe {
2003 ffi_try!(ffi::rocksdb_wait_for_compact(
2004 self.inner.inner(),
2005 opts.inner
2006 ));
2007 }
2008 Ok(())
2009 }
2010
2011 pub fn set_options(&self, opts: &[(&str, &str)]) -> Result<(), Error> {
2012 let copts = convert_options(opts)?;
2013 let cnames: Vec<*const c_char> = copts.iter().map(|opt| opt.0.as_ptr()).collect();
2014 let cvalues: Vec<*const c_char> = copts.iter().map(|opt| opt.1.as_ptr()).collect();
2015 let count = opts.len() as i32;
2016 unsafe {
2017 ffi_try!(ffi::rocksdb_set_options(
2018 self.inner.inner(),
2019 count,
2020 cnames.as_ptr(),
2021 cvalues.as_ptr(),
2022 ));
2023 }
2024 Ok(())
2025 }
2026
2027 pub fn set_options_cf(
2028 &self,
2029 cf: &impl AsColumnFamilyRef,
2030 opts: &[(&str, &str)],
2031 ) -> Result<(), Error> {
2032 let copts = convert_options(opts)?;
2033 let cnames: Vec<*const c_char> = copts.iter().map(|opt| opt.0.as_ptr()).collect();
2034 let cvalues: Vec<*const c_char> = copts.iter().map(|opt| opt.1.as_ptr()).collect();
2035 let count = opts.len() as i32;
2036 unsafe {
2037 ffi_try!(ffi::rocksdb_set_options_cf(
2038 self.inner.inner(),
2039 cf.inner(),
2040 count,
2041 cnames.as_ptr(),
2042 cvalues.as_ptr(),
2043 ));
2044 }
2045 Ok(())
2046 }
2047
2048 fn property_value_impl<R>(
2057 name: impl CStrLike,
2058 get_property: impl FnOnce(*const c_char) -> *mut c_char,
2059 parse: impl FnOnce(&str) -> Result<R, Error>,
2060 ) -> Result<Option<R>, Error> {
2061 let value = match name.bake() {
2062 Ok(prop_name) => get_property(prop_name.as_ptr()),
2063 Err(e) => {
2064 return Err(Error::new(format!(
2065 "Failed to convert property name to CString: {e}"
2066 )));
2067 }
2068 };
2069 if value.is_null() {
2070 return Ok(None);
2071 }
2072 let result = match unsafe { CStr::from_ptr(value) }.to_str() {
2073 Ok(s) => parse(s).map(|value| Some(value)),
2074 Err(e) => Err(Error::new(format!(
2075 "Failed to convert property value to string: {e}"
2076 ))),
2077 };
2078 unsafe {
2079 ffi::rocksdb_free(value as *mut c_void);
2080 }
2081 result
2082 }
2083
2084 pub fn property_value(&self, name: impl CStrLike) -> Result<Option<String>, Error> {
2089 Self::property_value_impl(
2090 name,
2091 |prop_name| unsafe { ffi::rocksdb_property_value(self.inner.inner(), prop_name) },
2092 |str_value| Ok(str_value.to_owned()),
2093 )
2094 }
2095
2096 pub fn property_value_cf(
2101 &self,
2102 cf: &impl AsColumnFamilyRef,
2103 name: impl CStrLike,
2104 ) -> Result<Option<String>, Error> {
2105 Self::property_value_impl(
2106 name,
2107 |prop_name| unsafe {
2108 ffi::rocksdb_property_value_cf(self.inner.inner(), cf.inner(), prop_name)
2109 },
2110 |str_value| Ok(str_value.to_owned()),
2111 )
2112 }
2113
2114 fn parse_property_int_value(value: &str) -> Result<u64, Error> {
2115 value.parse::<u64>().map_err(|err| {
2116 Error::new(format!(
2117 "Failed to convert property value {value} to int: {err}"
2118 ))
2119 })
2120 }
2121
2122 pub fn property_int_value(&self, name: impl CStrLike) -> Result<Option<u64>, Error> {
2127 Self::property_value_impl(
2128 name,
2129 |prop_name| unsafe { ffi::rocksdb_property_value(self.inner.inner(), prop_name) },
2130 Self::parse_property_int_value,
2131 )
2132 }
2133
2134 pub fn property_int_value_cf(
2139 &self,
2140 cf: &impl AsColumnFamilyRef,
2141 name: impl CStrLike,
2142 ) -> Result<Option<u64>, Error> {
2143 Self::property_value_impl(
2144 name,
2145 |prop_name| unsafe {
2146 ffi::rocksdb_property_value_cf(self.inner.inner(), cf.inner(), prop_name)
2147 },
2148 Self::parse_property_int_value,
2149 )
2150 }
2151
2152 pub fn latest_sequence_number(&self) -> u64 {
2154 unsafe { ffi::rocksdb_get_latest_sequence_number(self.inner.inner()) }
2155 }
2156
2157 pub fn get_updates_since(&self, seq_number: u64) -> Result<DBWALIterator, Error> {
2168 unsafe {
2169 let opts: *const ffi::rocksdb_wal_readoptions_t = ptr::null();
2173 let iter = ffi_try!(ffi::rocksdb_get_updates_since(
2174 self.inner.inner(),
2175 seq_number,
2176 opts
2177 ));
2178 Ok(DBWALIterator {
2179 inner: iter,
2180 start_seq_number: seq_number,
2181 })
2182 }
2183 }
2184
2185 pub fn try_catch_up_with_primary(&self) -> Result<(), Error> {
2188 unsafe {
2189 ffi_try!(ffi::rocksdb_try_catch_up_with_primary(self.inner.inner()));
2190 }
2191 Ok(())
2192 }
2193
2194 pub fn ingest_external_file<P: AsRef<Path>>(&self, paths: Vec<P>) -> Result<(), Error> {
2196 let opts = IngestExternalFileOptions::default();
2197 self.ingest_external_file_opts(&opts, paths)
2198 }
2199
2200 pub fn ingest_external_file_opts<P: AsRef<Path>>(
2202 &self,
2203 opts: &IngestExternalFileOptions,
2204 paths: Vec<P>,
2205 ) -> Result<(), Error> {
2206 let paths_v: Vec<CString> = paths.iter().map(to_cpath).collect::<Result<Vec<_>, _>>()?;
2207 let cpaths: Vec<_> = paths_v.iter().map(|path| path.as_ptr()).collect();
2208
2209 self.ingest_external_file_raw(opts, &paths_v, &cpaths)
2210 }
2211
2212 pub fn ingest_external_file_cf<P: AsRef<Path>>(
2215 &self,
2216 cf: &impl AsColumnFamilyRef,
2217 paths: Vec<P>,
2218 ) -> Result<(), Error> {
2219 let opts = IngestExternalFileOptions::default();
2220 self.ingest_external_file_cf_opts(cf, &opts, paths)
2221 }
2222
2223 pub fn ingest_external_file_cf_opts<P: AsRef<Path>>(
2225 &self,
2226 cf: &impl AsColumnFamilyRef,
2227 opts: &IngestExternalFileOptions,
2228 paths: Vec<P>,
2229 ) -> Result<(), Error> {
2230 let paths_v: Vec<CString> = paths.iter().map(to_cpath).collect::<Result<Vec<_>, _>>()?;
2231 let cpaths: Vec<_> = paths_v.iter().map(|path| path.as_ptr()).collect();
2232
2233 self.ingest_external_file_raw_cf(cf, opts, &paths_v, &cpaths)
2234 }
2235
2236 fn ingest_external_file_raw(
2237 &self,
2238 opts: &IngestExternalFileOptions,
2239 paths_v: &[CString],
2240 cpaths: &[*const c_char],
2241 ) -> Result<(), Error> {
2242 unsafe {
2243 ffi_try!(ffi::rocksdb_ingest_external_file(
2244 self.inner.inner(),
2245 cpaths.as_ptr(),
2246 paths_v.len(),
2247 opts.inner.cast_const()
2248 ));
2249 Ok(())
2250 }
2251 }
2252
2253 fn ingest_external_file_raw_cf(
2254 &self,
2255 cf: &impl AsColumnFamilyRef,
2256 opts: &IngestExternalFileOptions,
2257 paths_v: &[CString],
2258 cpaths: &[*const c_char],
2259 ) -> Result<(), Error> {
2260 unsafe {
2261 ffi_try!(ffi::rocksdb_ingest_external_file_cf(
2262 self.inner.inner(),
2263 cf.inner(),
2264 cpaths.as_ptr(),
2265 paths_v.len(),
2266 opts.inner.cast_const()
2267 ));
2268 Ok(())
2269 }
2270 }
2271
2272 pub fn get_column_family_metadata(&self) -> ColumnFamilyMetaData {
2274 unsafe {
2275 let ptr = ffi::rocksdb_get_column_family_metadata(self.inner.inner());
2276
2277 let metadata = ColumnFamilyMetaData {
2278 size: ffi::rocksdb_column_family_metadata_get_size(ptr),
2279 name: from_cstr(ffi::rocksdb_column_family_metadata_get_name(ptr)),
2280 file_count: ffi::rocksdb_column_family_metadata_get_file_count(ptr),
2281 };
2282
2283 ffi::rocksdb_column_family_metadata_destroy(ptr);
2285
2286 metadata
2288 }
2289 }
2290
2291 pub fn get_column_family_metadata_cf(
2293 &self,
2294 cf: &impl AsColumnFamilyRef,
2295 ) -> ColumnFamilyMetaData {
2296 unsafe {
2297 let ptr = ffi::rocksdb_get_column_family_metadata_cf(self.inner.inner(), cf.inner());
2298
2299 let metadata = ColumnFamilyMetaData {
2300 size: ffi::rocksdb_column_family_metadata_get_size(ptr),
2301 name: from_cstr(ffi::rocksdb_column_family_metadata_get_name(ptr)),
2302 file_count: ffi::rocksdb_column_family_metadata_get_file_count(ptr),
2303 };
2304
2305 ffi::rocksdb_column_family_metadata_destroy(ptr);
2307
2308 metadata
2310 }
2311 }
2312
2313 pub fn live_files(&self) -> Result<Vec<LiveFile>, Error> {
2316 unsafe {
2317 let files = ffi::rocksdb_livefiles(self.inner.inner());
2318 if files.is_null() {
2319 Err(Error::new("Could not get live files".to_owned()))
2320 } else {
2321 let n = ffi::rocksdb_livefiles_count(files);
2322
2323 let mut livefiles = Vec::with_capacity(n as usize);
2324 let mut key_size: usize = 0;
2325
2326 for i in 0..n {
2327 let column_family_name =
2328 from_cstr(ffi::rocksdb_livefiles_column_family_name(files, i));
2329 let name = from_cstr(ffi::rocksdb_livefiles_name(files, i));
2330 let size = ffi::rocksdb_livefiles_size(files, i);
2331 let level = ffi::rocksdb_livefiles_level(files, i);
2332
2333 let smallest_key = ffi::rocksdb_livefiles_smallestkey(files, i, &mut key_size);
2335 let smallest_key = raw_data(smallest_key, key_size);
2336
2337 let largest_key = ffi::rocksdb_livefiles_largestkey(files, i, &mut key_size);
2339 let largest_key = raw_data(largest_key, key_size);
2340
2341 livefiles.push(LiveFile {
2342 column_family_name,
2343 name,
2344 size,
2345 level,
2346 start_key: smallest_key,
2347 end_key: largest_key,
2348 num_entries: ffi::rocksdb_livefiles_entries(files, i),
2349 num_deletions: ffi::rocksdb_livefiles_deletions(files, i),
2350 });
2351 }
2352
2353 ffi::rocksdb_livefiles_destroy(files);
2355
2356 Ok(livefiles)
2358 }
2359 }
2360 }
2361
2362 pub fn delete_file_in_range<K: AsRef<[u8]>>(&self, from: K, to: K) -> Result<(), Error> {
2371 let from = from.as_ref();
2372 let to = to.as_ref();
2373 unsafe {
2374 ffi_try!(ffi::rocksdb_delete_file_in_range(
2375 self.inner.inner(),
2376 from.as_ptr() as *const c_char,
2377 from.len() as size_t,
2378 to.as_ptr() as *const c_char,
2379 to.len() as size_t,
2380 ));
2381 Ok(())
2382 }
2383 }
2384
2385 pub fn delete_file_in_range_cf<K: AsRef<[u8]>>(
2387 &self,
2388 cf: &impl AsColumnFamilyRef,
2389 from: K,
2390 to: K,
2391 ) -> Result<(), Error> {
2392 let from = from.as_ref();
2393 let to = to.as_ref();
2394 unsafe {
2395 ffi_try!(ffi::rocksdb_delete_file_in_range_cf(
2396 self.inner.inner(),
2397 cf.inner(),
2398 from.as_ptr() as *const c_char,
2399 from.len() as size_t,
2400 to.as_ptr() as *const c_char,
2401 to.len() as size_t,
2402 ));
2403 Ok(())
2404 }
2405 }
2406
2407 pub fn cancel_all_background_work(&self, wait: bool) {
2409 unsafe {
2410 ffi::rocksdb_cancel_all_background_work(self.inner.inner(), c_uchar::from(wait));
2411 }
2412 }
2413
2414 fn drop_column_family<C>(
2415 &self,
2416 cf_inner: *mut ffi::rocksdb_column_family_handle_t,
2417 cf: C,
2418 ) -> Result<(), Error> {
2419 unsafe {
2420 ffi_try!(ffi::rocksdb_drop_column_family(
2422 self.inner.inner(),
2423 cf_inner
2424 ));
2425 }
2426 drop(cf);
2429 Ok(())
2430 }
2431
2432 pub fn increase_full_history_ts_low<S: AsRef<[u8]>>(
2437 &self,
2438 cf: &impl AsColumnFamilyRef,
2439 ts: S,
2440 ) -> Result<(), Error> {
2441 let ts = ts.as_ref();
2442 unsafe {
2443 ffi_try!(ffi::rocksdb_increase_full_history_ts_low(
2444 self.inner.inner(),
2445 cf.inner(),
2446 ts.as_ptr() as *const c_char,
2447 ts.len() as size_t,
2448 ));
2449 Ok(())
2450 }
2451 }
2452
2453 pub fn get_full_history_ts_low(&self, cf: &impl AsColumnFamilyRef) -> Result<Vec<u8>, Error> {
2455 unsafe {
2456 let mut ts_lowlen = 0;
2457 let ts = ffi_try!(ffi::rocksdb_get_full_history_ts_low(
2458 self.inner.inner(),
2459 cf.inner(),
2460 &mut ts_lowlen,
2461 ));
2462
2463 if ts.is_null() {
2464 Err(Error::new("Could not get full_history_ts_low".to_owned()))
2465 } else {
2466 let mut vec = vec![0; ts_lowlen];
2467 ptr::copy_nonoverlapping(ts as *mut u8, vec.as_mut_ptr(), ts_lowlen);
2468 ffi::rocksdb_free(ts as *mut c_void);
2469 Ok(vec)
2470 }
2471 }
2472 }
2473
2474 pub fn get_db_identity(&self) -> Result<Vec<u8>, Error> {
2476 unsafe {
2477 let mut length: usize = 0;
2478 let identity_ptr = ffi::rocksdb_get_db_identity(self.inner.inner(), &mut length);
2479 let identity_vec = raw_data(identity_ptr, length);
2480 ffi::rocksdb_free(identity_ptr as *mut c_void);
2481 identity_vec.ok_or_else(|| Error::new("get_db_identity returned NULL".to_string()))
2484 }
2485 }
2486}
2487
2488impl<I: DBInner> DBCommon<SingleThreaded, I> {
2489 pub fn create_cf<N: AsRef<str>>(&mut self, name: N, opts: &Options) -> Result<(), Error> {
2491 let inner = self.create_inner_cf_handle(name.as_ref(), opts)?;
2492 self.cfs
2493 .cfs
2494 .insert(name.as_ref().to_string(), ColumnFamily { inner });
2495 Ok(())
2496 }
2497
2498 pub fn drop_cf(&mut self, name: &str) -> Result<(), Error> {
2500 if let Some(cf) = self.cfs.cfs.remove(name) {
2501 self.drop_column_family(cf.inner, cf)
2502 } else {
2503 Err(Error::new(format!("Invalid column family: {name}")))
2504 }
2505 }
2506
2507 pub fn cf_handle(&self, name: &str) -> Option<&ColumnFamily> {
2509 self.cfs.cfs.get(name)
2510 }
2511}
2512
2513impl<I: DBInner> DBCommon<MultiThreaded, I> {
2514 pub fn create_cf<N: AsRef<str>>(&self, name: N, opts: &Options) -> Result<(), Error> {
2516 let mut cfs = self.cfs.cfs.write().unwrap();
2519 let inner = self.create_inner_cf_handle(name.as_ref(), opts)?;
2520 cfs.insert(
2521 name.as_ref().to_string(),
2522 Arc::new(UnboundColumnFamily { inner }),
2523 );
2524 Ok(())
2525 }
2526
2527 pub fn drop_cf(&self, name: &str) -> Result<(), Error> {
2530 if let Some(cf) = self.cfs.cfs.write().unwrap().remove(name) {
2531 self.drop_column_family(cf.inner, cf)
2532 } else {
2533 Err(Error::new(format!("Invalid column family: {name}")))
2534 }
2535 }
2536
2537 pub fn cf_handle(&self, name: &str) -> Option<Arc<BoundColumnFamily>> {
2539 self.cfs
2540 .cfs
2541 .read()
2542 .unwrap()
2543 .get(name)
2544 .cloned()
2545 .map(UnboundColumnFamily::bound_column_family)
2546 }
2547}
2548
2549impl<T: ThreadMode, I: DBInner> Drop for DBCommon<T, I> {
2550 fn drop(&mut self) {
2551 self.cfs.drop_all_cfs_internal();
2552 }
2553}
2554
2555impl<T: ThreadMode, I: DBInner> fmt::Debug for DBCommon<T, I> {
2556 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2557 write!(f, "RocksDB {{ path: {:?} }}", self.path())
2558 }
2559}
2560
2561#[derive(Debug, Clone)]
2563pub struct ColumnFamilyMetaData {
2564 pub size: u64,
2567 pub name: String,
2569 pub file_count: usize,
2571}
2572
2573#[derive(Debug, Clone)]
2575pub struct LiveFile {
2576 pub column_family_name: String,
2578 pub name: String,
2580 pub size: usize,
2582 pub level: i32,
2584 pub start_key: Option<Vec<u8>>,
2586 pub end_key: Option<Vec<u8>>,
2588 pub num_entries: u64,
2590 pub num_deletions: u64,
2592}
2593
2594fn convert_options(opts: &[(&str, &str)]) -> Result<Vec<(CString, CString)>, Error> {
2595 opts.iter()
2596 .map(|(name, value)| {
2597 let cname = match CString::new(name.as_bytes()) {
2598 Ok(cname) => cname,
2599 Err(e) => return Err(Error::new(format!("Invalid option name `{e}`"))),
2600 };
2601 let cvalue = match CString::new(value.as_bytes()) {
2602 Ok(cvalue) => cvalue,
2603 Err(e) => return Err(Error::new(format!("Invalid option value: `{e}`"))),
2604 };
2605 Ok((cname, cvalue))
2606 })
2607 .collect()
2608}
2609
2610pub(crate) fn convert_values(
2611 values: Vec<*mut c_char>,
2612 values_sizes: Vec<usize>,
2613 errors: Vec<*mut c_char>,
2614) -> Vec<Result<Option<Vec<u8>>, Error>> {
2615 values
2616 .into_iter()
2617 .zip(values_sizes)
2618 .zip(errors)
2619 .map(|((v, s), e)| {
2620 if e.is_null() {
2621 let value = unsafe { crate::ffi_util::raw_data(v, s) };
2622 unsafe {
2623 ffi::rocksdb_free(v as *mut c_void);
2624 }
2625 Ok(value)
2626 } else {
2627 Err(Error::new(crate::ffi_util::error_message(e)))
2628 }
2629 })
2630 .collect()
2631}