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