1use std::cell::RefCell;
17use std::collections::{BTreeMap, HashMap};
18use std::ffi::{CStr, CString};
19use std::fmt;
20use std::fs;
21use std::iter;
22use std::path::Path;
23use std::path::PathBuf;
24use std::ptr;
25use std::slice;
26use std::str;
27use std::sync::Arc;
28use std::time::Duration;
29
30use crate::column_family::ColumnFamilyTtl;
31use crate::ffi_util::CSlice;
32use crate::{
33 column_family::AsColumnFamilyRef,
34 column_family::BoundColumnFamily,
35 column_family::UnboundColumnFamily,
36 db_options::{ImportColumnFamilyOptions, OptionsMustOutliveDB},
37 ffi,
38 ffi_util::{from_cstr, opt_bytes_to_ptr, raw_data, to_cpath, CStrLike},
39 ColumnFamily, ColumnFamilyDescriptor, CompactOptions, DBIteratorWithThreadMode,
40 DBPinnableSlice, DBRawIteratorWithThreadMode, DBWALIterator, Direction, Error, FlushOptions,
41 IngestExternalFileOptions, IteratorMode, Options, ReadOptions, SnapshotWithThreadMode,
42 WaitForCompactOptions, WriteBatch, WriteBatchWithIndex, WriteOptions,
43 DEFAULT_COLUMN_FAMILY_NAME,
44};
45use rust_librocksdb_sys::{
46 rocksdb_livefile_destroy, rocksdb_livefile_t, rocksdb_livefiles_destroy, rocksdb_livefiles_t,
47};
48
49use libc::{self, c_char, c_int, c_uchar, c_void, size_t};
50use parking_lot::RwLock;
51
52thread_local! { static DEFAULT_READ_OPTS: ReadOptions = ReadOptions::default(); }
59thread_local! { static DEFAULT_WRITE_OPTS: WriteOptions = WriteOptions::default(); }
60thread_local! { static DEFAULT_FLUSH_OPTS: FlushOptions = FlushOptions::default(); }
61thread_local! { static PREFIX_READ_OPTS: RefCell<ReadOptions> = RefCell::new({ let mut o = ReadOptions::default(); o.set_prefix_same_as_start(true); o }); }
63
64pub struct Range<'a> {
68 start_key: &'a [u8],
69 end_key: &'a [u8],
70}
71
72impl<'a> Range<'a> {
73 pub fn new(start_key: &'a [u8], end_key: &'a [u8]) -> Range<'a> {
74 Range { start_key, end_key }
75 }
76}
77
78pub struct PrefixProber<'a, D: DBAccess> {
82 raw: DBRawIteratorWithThreadMode<'a, D>,
83}
84
85impl<D: DBAccess> PrefixProber<'_, D> {
86 pub fn exists(&mut self, prefix: &[u8]) -> Result<bool, Error> {
89 self.raw.seek(prefix);
90 if self.raw.valid() {
91 if let Some(k) = self.raw.key() {
92 return Ok(k.starts_with(prefix));
93 }
94 }
95 self.raw.status()?;
96 Ok(false)
97 }
98}
99
100pub trait ThreadMode {
111 fn new_cf_map_internal(
113 cf_map: BTreeMap<String, *mut ffi::rocksdb_column_family_handle_t>,
114 ) -> Self;
115 fn drop_all_cfs_internal(&mut self);
117}
118
119pub struct SingleThreaded {
126 pub(crate) cfs: HashMap<String, ColumnFamily>,
127}
128
129pub struct MultiThreaded {
135 pub(crate) cfs: RwLock<HashMap<String, Arc<UnboundColumnFamily>>>,
136}
137
138impl ThreadMode for SingleThreaded {
139 fn new_cf_map_internal(
140 cfs: BTreeMap<String, *mut ffi::rocksdb_column_family_handle_t>,
141 ) -> Self {
142 Self {
143 cfs: cfs
144 .into_iter()
145 .map(|(n, c)| (n, ColumnFamily { inner: c }))
146 .collect(),
147 }
148 }
149
150 fn drop_all_cfs_internal(&mut self) {
151 self.cfs.clear();
153 }
154}
155
156impl ThreadMode for MultiThreaded {
157 fn new_cf_map_internal(
158 cfs: BTreeMap<String, *mut ffi::rocksdb_column_family_handle_t>,
159 ) -> Self {
160 Self {
161 cfs: RwLock::new(
162 cfs.into_iter()
163 .map(|(n, c)| (n, Arc::new(UnboundColumnFamily { inner: c })))
164 .collect(),
165 ),
166 }
167 }
168
169 fn drop_all_cfs_internal(&mut self) {
170 self.cfs.write().clear();
172 }
173}
174
175pub trait DBInner {
177 fn inner(&self) -> *mut ffi::rocksdb_t;
178}
179
180pub struct DBCommon<T: ThreadMode, D: DBInner> {
185 pub(crate) inner: D,
186 cfs: T, path: PathBuf,
188 _outlive: Vec<OptionsMustOutliveDB>,
189}
190
191pub trait DBAccess {
194 unsafe fn create_snapshot(&self) -> *const ffi::rocksdb_snapshot_t;
195
196 unsafe fn release_snapshot(&self, snapshot: *const ffi::rocksdb_snapshot_t);
197
198 unsafe fn create_iterator(&self, readopts: &ReadOptions) -> *mut ffi::rocksdb_iterator_t;
199
200 unsafe fn create_iterator_cf(
201 &self,
202 cf_handle: *mut ffi::rocksdb_column_family_handle_t,
203 readopts: &ReadOptions,
204 ) -> *mut ffi::rocksdb_iterator_t;
205
206 fn get_opt<K: AsRef<[u8]>>(
207 &self,
208 key: K,
209 readopts: &ReadOptions,
210 ) -> Result<Option<Vec<u8>>, Error>;
211
212 fn get_cf_opt<K: AsRef<[u8]>>(
213 &self,
214 cf: &impl AsColumnFamilyRef,
215 key: K,
216 readopts: &ReadOptions,
217 ) -> Result<Option<Vec<u8>>, Error>;
218
219 fn get_pinned_opt<K: AsRef<[u8]>>(
220 &'_ self,
221 key: K,
222 readopts: &ReadOptions,
223 ) -> Result<Option<DBPinnableSlice<'_>>, Error>;
224
225 fn get_pinned_cf_opt<K: AsRef<[u8]>>(
226 &'_ self,
227 cf: &impl AsColumnFamilyRef,
228 key: K,
229 readopts: &ReadOptions,
230 ) -> Result<Option<DBPinnableSlice<'_>>, Error>;
231
232 fn multi_get_opt<K, I>(
233 &self,
234 keys: I,
235 readopts: &ReadOptions,
236 ) -> Vec<Result<Option<Vec<u8>>, Error>>
237 where
238 K: AsRef<[u8]>,
239 I: IntoIterator<Item = K>;
240
241 fn multi_get_cf_opt<'b, K, I, W>(
242 &self,
243 keys_cf: I,
244 readopts: &ReadOptions,
245 ) -> Vec<Result<Option<Vec<u8>>, Error>>
246 where
247 K: AsRef<[u8]>,
248 I: IntoIterator<Item = (&'b W, K)>,
249 W: AsColumnFamilyRef + 'b;
250}
251
252impl<T: ThreadMode, D: DBInner> DBAccess for DBCommon<T, D> {
253 unsafe fn create_snapshot(&self) -> *const ffi::rocksdb_snapshot_t {
254 unsafe { ffi::rocksdb_create_snapshot(self.inner.inner()) }
255 }
256
257 unsafe fn release_snapshot(&self, snapshot: *const ffi::rocksdb_snapshot_t) {
258 unsafe {
259 ffi::rocksdb_release_snapshot(self.inner.inner(), snapshot);
260 }
261 }
262
263 unsafe fn create_iterator(&self, readopts: &ReadOptions) -> *mut ffi::rocksdb_iterator_t {
264 unsafe { ffi::rocksdb_create_iterator(self.inner.inner(), readopts.inner) }
265 }
266
267 unsafe fn create_iterator_cf(
268 &self,
269 cf_handle: *mut ffi::rocksdb_column_family_handle_t,
270 readopts: &ReadOptions,
271 ) -> *mut ffi::rocksdb_iterator_t {
272 unsafe { ffi::rocksdb_create_iterator_cf(self.inner.inner(), readopts.inner, cf_handle) }
273 }
274
275 fn get_opt<K: AsRef<[u8]>>(
276 &self,
277 key: K,
278 readopts: &ReadOptions,
279 ) -> Result<Option<Vec<u8>>, Error> {
280 self.get_opt(key, readopts)
281 }
282
283 fn get_cf_opt<K: AsRef<[u8]>>(
284 &self,
285 cf: &impl AsColumnFamilyRef,
286 key: K,
287 readopts: &ReadOptions,
288 ) -> Result<Option<Vec<u8>>, Error> {
289 self.get_cf_opt(cf, key, readopts)
290 }
291
292 fn get_pinned_opt<K: AsRef<[u8]>>(
293 &'_ self,
294 key: K,
295 readopts: &ReadOptions,
296 ) -> Result<Option<DBPinnableSlice<'_>>, Error> {
297 self.get_pinned_opt(key, readopts)
298 }
299
300 fn get_pinned_cf_opt<K: AsRef<[u8]>>(
301 &'_ self,
302 cf: &impl AsColumnFamilyRef,
303 key: K,
304 readopts: &ReadOptions,
305 ) -> Result<Option<DBPinnableSlice<'_>>, Error> {
306 self.get_pinned_cf_opt(cf, key, readopts)
307 }
308
309 fn multi_get_opt<K, Iter>(
310 &self,
311 keys: Iter,
312 readopts: &ReadOptions,
313 ) -> Vec<Result<Option<Vec<u8>>, Error>>
314 where
315 K: AsRef<[u8]>,
316 Iter: IntoIterator<Item = K>,
317 {
318 self.multi_get_opt(keys, readopts)
319 }
320
321 fn multi_get_cf_opt<'b, K, Iter, W>(
322 &self,
323 keys_cf: Iter,
324 readopts: &ReadOptions,
325 ) -> Vec<Result<Option<Vec<u8>>, Error>>
326 where
327 K: AsRef<[u8]>,
328 Iter: IntoIterator<Item = (&'b W, K)>,
329 W: AsColumnFamilyRef + 'b,
330 {
331 self.multi_get_cf_opt(keys_cf, readopts)
332 }
333}
334
335pub struct DBWithThreadModeInner {
336 inner: *mut ffi::rocksdb_t,
337}
338
339impl DBInner for DBWithThreadModeInner {
340 fn inner(&self) -> *mut ffi::rocksdb_t {
341 self.inner
342 }
343}
344
345impl Drop for DBWithThreadModeInner {
346 fn drop(&mut self) {
347 unsafe {
348 ffi::rocksdb_close(self.inner);
349 }
350 }
351}
352
353pub type DBWithThreadMode<T> = DBCommon<T, DBWithThreadModeInner>;
358
359#[cfg(not(feature = "multi-threaded-cf"))]
382pub type DB = DBWithThreadMode<SingleThreaded>;
383
384#[cfg(feature = "multi-threaded-cf")]
385pub type DB = DBWithThreadMode<MultiThreaded>;
386
387unsafe impl<T: ThreadMode + Send, I: DBInner> Send for DBCommon<T, I> {}
391
392unsafe impl<T: ThreadMode, I: DBInner> Sync for DBCommon<T, I> {}
395
396enum AccessType<'a> {
398 ReadWrite,
399 ReadOnly { error_if_log_file_exist: bool },
400 Secondary { secondary_path: &'a Path },
401 WithTTL { ttl: Duration },
402}
403
404impl<T: ThreadMode> DBWithThreadMode<T> {
406 pub fn open_default<P: AsRef<Path>>(path: P) -> Result<Self, Error> {
408 let mut opts = Options::default();
409 opts.create_if_missing(true);
410 Self::open(&opts, path)
411 }
412
413 pub fn open<P: AsRef<Path>>(opts: &Options, path: P) -> Result<Self, Error> {
415 Self::open_cf(opts, path, None::<&str>)
416 }
417
418 pub fn open_for_read_only<P: AsRef<Path>>(
420 opts: &Options,
421 path: P,
422 error_if_log_file_exist: bool,
423 ) -> Result<Self, Error> {
424 Self::open_cf_for_read_only(opts, path, None::<&str>, error_if_log_file_exist)
425 }
426
427 pub fn open_as_secondary<P: AsRef<Path>>(
429 opts: &Options,
430 primary_path: P,
431 secondary_path: P,
432 ) -> Result<Self, Error> {
433 Self::open_cf_as_secondary(opts, primary_path, secondary_path, None::<&str>)
434 }
435
436 pub fn open_with_ttl<P: AsRef<Path>>(
441 opts: &Options,
442 path: P,
443 ttl: Duration,
444 ) -> Result<Self, Error> {
445 Self::open_cf_descriptors_with_ttl(opts, path, std::iter::empty(), ttl)
446 }
447
448 pub fn open_cf_with_ttl<P, I, N>(
452 opts: &Options,
453 path: P,
454 cfs: I,
455 ttl: Duration,
456 ) -> 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_with_ttl(opts, path, cfs, ttl)
467 }
468
469 pub fn open_cf_descriptors_with_ttl<P, I>(
483 opts: &Options,
484 path: P,
485 cfs: I,
486 ttl: Duration,
487 ) -> Result<Self, Error>
488 where
489 P: AsRef<Path>,
490 I: IntoIterator<Item = ColumnFamilyDescriptor>,
491 {
492 Self::open_cf_descriptors_internal(opts, path, cfs, &AccessType::WithTTL { ttl })
493 }
494
495 pub fn open_cf<P, I, N>(opts: &Options, path: P, cfs: I) -> Result<Self, Error>
499 where
500 P: AsRef<Path>,
501 I: IntoIterator<Item = N>,
502 N: AsRef<str>,
503 {
504 let cfs = cfs
505 .into_iter()
506 .map(|name| ColumnFamilyDescriptor::new(name.as_ref(), Options::default()));
507
508 Self::open_cf_descriptors_internal(opts, path, cfs, &AccessType::ReadWrite)
509 }
510
511 pub fn open_cf_with_opts<P, I, N>(opts: &Options, path: P, cfs: I) -> Result<Self, Error>
515 where
516 P: AsRef<Path>,
517 I: IntoIterator<Item = (N, Options)>,
518 N: AsRef<str>,
519 {
520 let cfs = cfs
521 .into_iter()
522 .map(|(name, opts)| ColumnFamilyDescriptor::new(name.as_ref(), opts));
523
524 Self::open_cf_descriptors(opts, path, cfs)
525 }
526
527 pub fn open_cf_for_read_only<P, I, N>(
531 opts: &Options,
532 path: P,
533 cfs: I,
534 error_if_log_file_exist: bool,
535 ) -> Result<Self, Error>
536 where
537 P: AsRef<Path>,
538 I: IntoIterator<Item = N>,
539 N: AsRef<str>,
540 {
541 let cfs = cfs
542 .into_iter()
543 .map(|name| ColumnFamilyDescriptor::new(name.as_ref(), Options::default()));
544
545 Self::open_cf_descriptors_internal(
546 opts,
547 path,
548 cfs,
549 &AccessType::ReadOnly {
550 error_if_log_file_exist,
551 },
552 )
553 }
554
555 pub fn open_cf_with_opts_for_read_only<P, I, N>(
559 db_opts: &Options,
560 path: P,
561 cfs: I,
562 error_if_log_file_exist: bool,
563 ) -> Result<Self, Error>
564 where
565 P: AsRef<Path>,
566 I: IntoIterator<Item = (N, Options)>,
567 N: AsRef<str>,
568 {
569 let cfs = cfs
570 .into_iter()
571 .map(|(name, cf_opts)| ColumnFamilyDescriptor::new(name.as_ref(), cf_opts));
572
573 Self::open_cf_descriptors_internal(
574 db_opts,
575 path,
576 cfs,
577 &AccessType::ReadOnly {
578 error_if_log_file_exist,
579 },
580 )
581 }
582
583 pub fn open_cf_descriptors_read_only<P, I>(
588 opts: &Options,
589 path: P,
590 cfs: I,
591 error_if_log_file_exist: bool,
592 ) -> Result<Self, Error>
593 where
594 P: AsRef<Path>,
595 I: IntoIterator<Item = ColumnFamilyDescriptor>,
596 {
597 Self::open_cf_descriptors_internal(
598 opts,
599 path,
600 cfs,
601 &AccessType::ReadOnly {
602 error_if_log_file_exist,
603 },
604 )
605 }
606
607 pub fn open_cf_as_secondary<P, I, N>(
611 opts: &Options,
612 primary_path: P,
613 secondary_path: P,
614 cfs: I,
615 ) -> Result<Self, Error>
616 where
617 P: AsRef<Path>,
618 I: IntoIterator<Item = N>,
619 N: AsRef<str>,
620 {
621 let cfs = cfs
622 .into_iter()
623 .map(|name| ColumnFamilyDescriptor::new(name.as_ref(), Options::default()));
624
625 Self::open_cf_descriptors_internal(
626 opts,
627 primary_path,
628 cfs,
629 &AccessType::Secondary {
630 secondary_path: secondary_path.as_ref(),
631 },
632 )
633 }
634
635 pub fn open_cf_descriptors_as_secondary<P, I>(
640 opts: &Options,
641 path: P,
642 secondary_path: P,
643 cfs: I,
644 ) -> Result<Self, Error>
645 where
646 P: AsRef<Path>,
647 I: IntoIterator<Item = ColumnFamilyDescriptor>,
648 {
649 Self::open_cf_descriptors_internal(
650 opts,
651 path,
652 cfs,
653 &AccessType::Secondary {
654 secondary_path: secondary_path.as_ref(),
655 },
656 )
657 }
658
659 pub fn open_cf_descriptors<P, I>(opts: &Options, path: P, cfs: I) -> Result<Self, Error>
663 where
664 P: AsRef<Path>,
665 I: IntoIterator<Item = ColumnFamilyDescriptor>,
666 {
667 Self::open_cf_descriptors_internal(opts, path, cfs, &AccessType::ReadWrite)
668 }
669
670 fn open_cf_descriptors_internal<P, I>(
672 opts: &Options,
673 path: P,
674 cfs: I,
675 access_type: &AccessType,
676 ) -> Result<Self, Error>
677 where
678 P: AsRef<Path>,
679 I: IntoIterator<Item = ColumnFamilyDescriptor>,
680 {
681 let cfs: Vec<_> = cfs.into_iter().collect();
682 let outlive = iter::once(opts.outlive.clone())
683 .chain(cfs.iter().map(|cf| cf.options.outlive.clone()))
684 .collect();
685
686 let cpath = to_cpath(&path)?;
687
688 if let Err(e) = fs::create_dir_all(&path) {
689 return Err(Error::new(format!(
690 "Failed to create RocksDB directory: `{e:?}`."
691 )));
692 }
693
694 let db: *mut ffi::rocksdb_t;
695 let mut cf_map = BTreeMap::new();
696
697 if cfs.is_empty() {
698 db = Self::open_raw(opts, &cpath, access_type)?;
699 } else {
700 let mut cfs_v = cfs;
701 if !cfs_v.iter().any(|cf| cf.name == DEFAULT_COLUMN_FAMILY_NAME) {
703 cfs_v.push(ColumnFamilyDescriptor {
704 name: String::from(DEFAULT_COLUMN_FAMILY_NAME),
705 options: Options::default(),
706 ttl: ColumnFamilyTtl::SameAsDb,
707 });
708 }
709 let c_cfs: Vec<CString> = cfs_v
712 .iter()
713 .map(|cf| CString::new(cf.name.as_bytes()).unwrap())
714 .collect();
715
716 let cfnames: Vec<_> = c_cfs.iter().map(|cf| cf.as_ptr()).collect();
717
718 let mut cfhandles: Vec<_> = cfs_v.iter().map(|_| ptr::null_mut()).collect();
720
721 let cfopts: Vec<_> = cfs_v
722 .iter()
723 .map(|cf| cf.options.inner.cast_const())
724 .collect();
725
726 db = Self::open_cf_raw(
727 opts,
728 &cpath,
729 &cfs_v,
730 &cfnames,
731 &cfopts,
732 &mut cfhandles,
733 access_type,
734 )?;
735 for handle in &cfhandles {
736 if handle.is_null() {
737 return Err(Error::new(
738 "Received null column family handle from DB.".to_owned(),
739 ));
740 }
741 }
742
743 for (cf_desc, inner) in cfs_v.iter().zip(cfhandles) {
744 cf_map.insert(cf_desc.name.clone(), inner);
745 }
746 }
747
748 if db.is_null() {
749 return Err(Error::new("Could not initialize database.".to_owned()));
750 }
751
752 Ok(Self {
753 inner: DBWithThreadModeInner { inner: db },
754 path: path.as_ref().to_path_buf(),
755 cfs: T::new_cf_map_internal(cf_map),
756 _outlive: outlive,
757 })
758 }
759
760 fn open_raw(
761 opts: &Options,
762 cpath: &CString,
763 access_type: &AccessType,
764 ) -> Result<*mut ffi::rocksdb_t, Error> {
765 let db = unsafe {
766 match *access_type {
767 AccessType::ReadOnly {
768 error_if_log_file_exist,
769 } => ffi_try!(ffi::rocksdb_open_for_read_only(
770 opts.inner,
771 cpath.as_ptr(),
772 c_uchar::from(error_if_log_file_exist),
773 )),
774 AccessType::ReadWrite => {
775 ffi_try!(ffi::rocksdb_open(opts.inner, cpath.as_ptr()))
776 }
777 AccessType::Secondary { secondary_path } => {
778 ffi_try!(ffi::rocksdb_open_as_secondary(
779 opts.inner,
780 cpath.as_ptr(),
781 to_cpath(secondary_path)?.as_ptr(),
782 ))
783 }
784 AccessType::WithTTL { ttl } => ffi_try!(ffi::rocksdb_open_with_ttl(
785 opts.inner,
786 cpath.as_ptr(),
787 ttl.as_secs() as c_int,
788 )),
789 }
790 };
791 Ok(db)
792 }
793
794 #[allow(clippy::pedantic)]
795 fn open_cf_raw(
796 opts: &Options,
797 cpath: &CString,
798 cfs_v: &[ColumnFamilyDescriptor],
799 cfnames: &[*const c_char],
800 cfopts: &[*const ffi::rocksdb_options_t],
801 cfhandles: &mut [*mut ffi::rocksdb_column_family_handle_t],
802 access_type: &AccessType,
803 ) -> Result<*mut ffi::rocksdb_t, Error> {
804 let db = unsafe {
805 match *access_type {
806 AccessType::ReadOnly {
807 error_if_log_file_exist,
808 } => ffi_try!(ffi::rocksdb_open_for_read_only_column_families(
809 opts.inner,
810 cpath.as_ptr(),
811 cfs_v.len() as c_int,
812 cfnames.as_ptr(),
813 cfopts.as_ptr(),
814 cfhandles.as_mut_ptr(),
815 c_uchar::from(error_if_log_file_exist),
816 )),
817 AccessType::ReadWrite => ffi_try!(ffi::rocksdb_open_column_families(
818 opts.inner,
819 cpath.as_ptr(),
820 cfs_v.len() as c_int,
821 cfnames.as_ptr(),
822 cfopts.as_ptr(),
823 cfhandles.as_mut_ptr(),
824 )),
825 AccessType::Secondary { secondary_path } => {
826 ffi_try!(ffi::rocksdb_open_as_secondary_column_families(
827 opts.inner,
828 cpath.as_ptr(),
829 to_cpath(secondary_path)?.as_ptr(),
830 cfs_v.len() as c_int,
831 cfnames.as_ptr(),
832 cfopts.as_ptr(),
833 cfhandles.as_mut_ptr(),
834 ))
835 }
836 AccessType::WithTTL { ttl } => {
837 let ttls: Vec<_> = cfs_v
838 .iter()
839 .map(|cf| match cf.ttl {
840 ColumnFamilyTtl::Disabled => i32::MAX,
841 ColumnFamilyTtl::Duration(duration) => duration.as_secs() as i32,
842 ColumnFamilyTtl::SameAsDb => ttl.as_secs() as i32,
843 })
844 .collect();
845
846 ffi_try!(ffi::rocksdb_open_column_families_with_ttl(
847 opts.inner,
848 cpath.as_ptr(),
849 cfs_v.len() as c_int,
850 cfnames.as_ptr(),
851 cfopts.as_ptr(),
852 cfhandles.as_mut_ptr(),
853 ttls.as_ptr(),
854 ))
855 }
856 }
857 };
858 Ok(db)
859 }
860
861 pub fn delete_range_cf_opt<K: AsRef<[u8]>>(
863 &self,
864 cf: &impl AsColumnFamilyRef,
865 from: K,
866 to: K,
867 writeopts: &WriteOptions,
868 ) -> Result<(), Error> {
869 let from = from.as_ref();
870 let to = to.as_ref();
871
872 unsafe {
873 ffi_try!(ffi::rocksdb_delete_range_cf(
874 self.inner.inner(),
875 writeopts.inner,
876 cf.inner(),
877 from.as_ptr() as *const c_char,
878 from.len() as size_t,
879 to.as_ptr() as *const c_char,
880 to.len() as size_t,
881 ));
882 Ok(())
883 }
884 }
885
886 pub fn delete_range_cf<K: AsRef<[u8]>>(
888 &self,
889 cf: &impl AsColumnFamilyRef,
890 from: K,
891 to: K,
892 ) -> Result<(), Error> {
893 DEFAULT_WRITE_OPTS.with(|opts| self.delete_range_cf_opt(cf, from, to, opts))
894 }
895
896 pub fn write_opt(&self, batch: &WriteBatch, writeopts: &WriteOptions) -> Result<(), Error> {
897 unsafe {
898 ffi_try!(ffi::rocksdb_write(
899 self.inner.inner(),
900 writeopts.inner,
901 batch.inner
902 ));
903 }
904 Ok(())
905 }
906
907 pub fn write(&self, batch: &WriteBatch) -> Result<(), Error> {
908 DEFAULT_WRITE_OPTS.with(|opts| self.write_opt(batch, opts))
909 }
910
911 pub fn write_without_wal(&self, batch: &WriteBatch) -> Result<(), Error> {
912 let mut wo = WriteOptions::new();
913 wo.disable_wal(true);
914 self.write_opt(batch, &wo)
915 }
916
917 pub fn write_wbwi(&self, wbwi: &WriteBatchWithIndex) -> Result<(), Error> {
918 DEFAULT_WRITE_OPTS.with(|opts| self.write_wbwi_opt(wbwi, opts))
919 }
920
921 pub fn write_wbwi_opt(
922 &self,
923 wbwi: &WriteBatchWithIndex,
924 writeopts: &WriteOptions,
925 ) -> Result<(), Error> {
926 unsafe {
927 ffi_try!(ffi::rocksdb_write_writebatch_wi(
928 self.inner.inner(),
929 writeopts.inner,
930 wbwi.inner
931 ));
932
933 Ok(())
934 }
935 }
936
937 pub fn disable_file_deletions(&self) -> Result<(), Error> {
942 unsafe {
943 ffi_try!(ffi::rocksdb_disable_file_deletions(self.inner.inner()));
944 }
945 Ok(())
946 }
947
948 pub fn enable_file_deletions(&self) -> Result<(), Error> {
960 unsafe {
961 ffi_try!(ffi::rocksdb_enable_file_deletions(self.inner.inner()));
962 }
963 Ok(())
964 }
965}
966
967impl<T: ThreadMode, D: DBInner> DBCommon<T, D> {
969 pub(crate) fn new(inner: D, cfs: T, path: PathBuf, outlive: Vec<OptionsMustOutliveDB>) -> Self {
970 Self {
971 inner,
972 cfs,
973 path,
974 _outlive: outlive,
975 }
976 }
977
978 pub fn list_cf<P: AsRef<Path>>(opts: &Options, path: P) -> Result<Vec<String>, Error> {
979 let cpath = to_cpath(path)?;
980 let mut length = 0;
981
982 unsafe {
983 let ptr = ffi_try!(ffi::rocksdb_list_column_families(
984 opts.inner,
985 cpath.as_ptr(),
986 &mut length,
987 ));
988
989 let vec = slice::from_raw_parts(ptr, length)
990 .iter()
991 .map(|ptr| CStr::from_ptr(*ptr).to_string_lossy().into_owned())
992 .collect();
993 ffi::rocksdb_list_column_families_destroy(ptr, length);
994 Ok(vec)
995 }
996 }
997
998 pub fn destroy<P: AsRef<Path>>(opts: &Options, path: P) -> Result<(), Error> {
999 let cpath = to_cpath(path)?;
1000 unsafe {
1001 ffi_try!(ffi::rocksdb_destroy_db(opts.inner, cpath.as_ptr()));
1002 }
1003 Ok(())
1004 }
1005
1006 pub fn repair<P: AsRef<Path>>(opts: &Options, path: P) -> Result<(), Error> {
1007 let cpath = to_cpath(path)?;
1008 unsafe {
1009 ffi_try!(ffi::rocksdb_repair_db(opts.inner, cpath.as_ptr()));
1010 }
1011 Ok(())
1012 }
1013
1014 pub fn path(&self) -> &Path {
1015 self.path.as_path()
1016 }
1017
1018 pub fn flush_wal(&self, sync: bool) -> Result<(), Error> {
1021 unsafe {
1022 ffi_try!(ffi::rocksdb_flush_wal(
1023 self.inner.inner(),
1024 c_uchar::from(sync)
1025 ));
1026 }
1027 Ok(())
1028 }
1029
1030 pub fn flush_opt(&self, flushopts: &FlushOptions) -> Result<(), Error> {
1032 unsafe {
1033 ffi_try!(ffi::rocksdb_flush(self.inner.inner(), flushopts.inner));
1034 }
1035 Ok(())
1036 }
1037
1038 pub fn flush(&self) -> Result<(), Error> {
1040 self.flush_opt(&FlushOptions::default())
1041 }
1042
1043 pub fn flush_cf_opt(
1045 &self,
1046 cf: &impl AsColumnFamilyRef,
1047 flushopts: &FlushOptions,
1048 ) -> Result<(), Error> {
1049 unsafe {
1050 ffi_try!(ffi::rocksdb_flush_cf(
1051 self.inner.inner(),
1052 flushopts.inner,
1053 cf.inner()
1054 ));
1055 }
1056 Ok(())
1057 }
1058
1059 pub fn flush_cfs_opt(
1065 &self,
1066 cfs: &[&impl AsColumnFamilyRef],
1067 opts: &FlushOptions,
1068 ) -> Result<(), Error> {
1069 let mut cfs = cfs.iter().map(|cf| cf.inner()).collect::<Vec<_>>();
1070 unsafe {
1071 ffi_try!(ffi::rocksdb_flush_cfs(
1072 self.inner.inner(),
1073 opts.inner,
1074 cfs.as_mut_ptr(),
1075 cfs.len() as libc::c_int,
1076 ));
1077 }
1078 Ok(())
1079 }
1080
1081 pub fn flush_cf(&self, cf: &impl AsColumnFamilyRef) -> Result<(), Error> {
1084 DEFAULT_FLUSH_OPTS.with(|opts| self.flush_cf_opt(cf, opts))
1085 }
1086
1087 pub fn get_opt<K: AsRef<[u8]>>(
1091 &self,
1092 key: K,
1093 readopts: &ReadOptions,
1094 ) -> Result<Option<Vec<u8>>, Error> {
1095 self.get_pinned_opt(key, readopts)
1096 .map(|x| x.map(|v| v.as_ref().to_vec()))
1097 }
1098
1099 pub fn get<K: AsRef<[u8]>>(&self, key: K) -> Result<Option<Vec<u8>>, Error> {
1103 DEFAULT_READ_OPTS.with(|opts| self.get_opt(key.as_ref(), opts))
1104 }
1105
1106 pub fn get_cf_opt<K: AsRef<[u8]>>(
1110 &self,
1111 cf: &impl AsColumnFamilyRef,
1112 key: K,
1113 readopts: &ReadOptions,
1114 ) -> Result<Option<Vec<u8>>, Error> {
1115 self.get_pinned_cf_opt(cf, key, readopts)
1116 .map(|x| x.map(|v| v.as_ref().to_vec()))
1117 }
1118
1119 pub fn get_cf<K: AsRef<[u8]>>(
1123 &self,
1124 cf: &impl AsColumnFamilyRef,
1125 key: K,
1126 ) -> Result<Option<Vec<u8>>, Error> {
1127 DEFAULT_READ_OPTS.with(|opts| self.get_cf_opt(cf, key.as_ref(), opts))
1128 }
1129
1130 pub fn get_pinned_opt<K: AsRef<[u8]>>(
1133 &'_ self,
1134 key: K,
1135 readopts: &ReadOptions,
1136 ) -> Result<Option<DBPinnableSlice<'_>>, Error> {
1137 if readopts.inner.is_null() {
1138 return Err(Error::new(
1139 "Unable to create RocksDB read options. This is a fairly trivial call, and its \
1140 failure may be indicative of a mis-compiled or mis-loaded RocksDB library."
1141 .to_owned(),
1142 ));
1143 }
1144
1145 let key = key.as_ref();
1146 unsafe {
1147 let val = ffi_try!(ffi::rocksdb_get_pinned(
1148 self.inner.inner(),
1149 readopts.inner,
1150 key.as_ptr() as *const c_char,
1151 key.len() as size_t,
1152 ));
1153 if val.is_null() {
1154 Ok(None)
1155 } else {
1156 Ok(Some(DBPinnableSlice::from_c(val)))
1157 }
1158 }
1159 }
1160
1161 pub fn get_pinned<K: AsRef<[u8]>>(
1165 &'_ self,
1166 key: K,
1167 ) -> Result<Option<DBPinnableSlice<'_>>, Error> {
1168 DEFAULT_READ_OPTS.with(|opts| self.get_pinned_opt(key, opts))
1169 }
1170
1171 pub fn get_pinned_cf_opt<K: AsRef<[u8]>>(
1175 &'_ self,
1176 cf: &impl AsColumnFamilyRef,
1177 key: K,
1178 readopts: &ReadOptions,
1179 ) -> Result<Option<DBPinnableSlice<'_>>, Error> {
1180 if readopts.inner.is_null() {
1181 return Err(Error::new(
1182 "Unable to create RocksDB read options. This is a fairly trivial call, and its \
1183 failure may be indicative of a mis-compiled or mis-loaded RocksDB library."
1184 .to_owned(),
1185 ));
1186 }
1187
1188 let key = key.as_ref();
1189 unsafe {
1190 let val = ffi_try!(ffi::rocksdb_get_pinned_cf(
1191 self.inner.inner(),
1192 readopts.inner,
1193 cf.inner(),
1194 key.as_ptr() as *const c_char,
1195 key.len() as size_t,
1196 ));
1197 if val.is_null() {
1198 Ok(None)
1199 } else {
1200 Ok(Some(DBPinnableSlice::from_c(val)))
1201 }
1202 }
1203 }
1204
1205 pub fn get_pinned_cf<K: AsRef<[u8]>>(
1209 &'_ self,
1210 cf: &impl AsColumnFamilyRef,
1211 key: K,
1212 ) -> Result<Option<DBPinnableSlice<'_>>, Error> {
1213 DEFAULT_READ_OPTS.with(|opts| self.get_pinned_cf_opt(cf, key, opts))
1214 }
1215
1216 pub fn multi_get<K, I>(&self, keys: I) -> Vec<Result<Option<Vec<u8>>, Error>>
1218 where
1219 K: AsRef<[u8]>,
1220 I: IntoIterator<Item = K>,
1221 {
1222 DEFAULT_READ_OPTS.with(|opts| self.multi_get_opt(keys, opts))
1223 }
1224
1225 pub fn multi_get_opt<K, I>(
1227 &self,
1228 keys: I,
1229 readopts: &ReadOptions,
1230 ) -> Vec<Result<Option<Vec<u8>>, Error>>
1231 where
1232 K: AsRef<[u8]>,
1233 I: IntoIterator<Item = K>,
1234 {
1235 let owned_keys: Vec<K> = keys.into_iter().collect();
1236 let keys_sizes: Vec<usize> = owned_keys.iter().map(|k| k.as_ref().len()).collect();
1237 let ptr_keys: Vec<*const c_char> = owned_keys
1238 .iter()
1239 .map(|k| k.as_ref().as_ptr() as *const c_char)
1240 .collect();
1241
1242 let mut values: Vec<*mut c_char> = Vec::with_capacity(ptr_keys.len());
1243 let mut values_sizes: Vec<usize> = Vec::with_capacity(ptr_keys.len());
1244 let mut errors: Vec<*mut c_char> = Vec::with_capacity(ptr_keys.len());
1245 unsafe {
1246 ffi::rocksdb_multi_get(
1247 self.inner.inner(),
1248 readopts.inner,
1249 ptr_keys.len(),
1250 ptr_keys.as_ptr(),
1251 keys_sizes.as_ptr(),
1252 values.as_mut_ptr(),
1253 values_sizes.as_mut_ptr(),
1254 errors.as_mut_ptr(),
1255 );
1256 }
1257
1258 unsafe {
1259 values.set_len(ptr_keys.len());
1260 values_sizes.set_len(ptr_keys.len());
1261 errors.set_len(ptr_keys.len());
1262 }
1263
1264 convert_values(values, values_sizes, errors)
1265 }
1266
1267 pub fn multi_get_pinned<K, I>(
1272 &'_ self,
1273 keys: I,
1274 ) -> Vec<Result<Option<DBPinnableSlice<'_>>, Error>>
1275 where
1276 K: AsRef<[u8]>,
1277 I: IntoIterator<Item = K>,
1278 {
1279 DEFAULT_READ_OPTS.with(|opts| self.multi_get_pinned_opt(keys, opts))
1280 }
1281
1282 pub fn multi_get_pinned_opt<K, I>(
1287 &'_ self,
1288 keys: I,
1289 readopts: &ReadOptions,
1290 ) -> Vec<Result<Option<DBPinnableSlice<'_>>, Error>>
1291 where
1292 K: AsRef<[u8]>,
1293 I: IntoIterator<Item = K>,
1294 {
1295 keys.into_iter()
1296 .map(|k| self.get_pinned_opt(k, readopts))
1297 .collect()
1298 }
1299
1300 pub fn multi_get_pinned_cf<'a, 'b: 'a, K, I, W>(
1303 &'a self,
1304 keys: I,
1305 ) -> Vec<Result<Option<DBPinnableSlice<'a>>, Error>>
1306 where
1307 K: AsRef<[u8]>,
1308 I: IntoIterator<Item = (&'b W, K)>,
1309 W: 'b + AsColumnFamilyRef,
1310 {
1311 DEFAULT_READ_OPTS.with(|opts| self.multi_get_pinned_cf_opt(keys, opts))
1312 }
1313
1314 pub fn multi_get_pinned_cf_opt<'a, 'b: 'a, K, I, W>(
1317 &'a self,
1318 keys: I,
1319 readopts: &ReadOptions,
1320 ) -> Vec<Result<Option<DBPinnableSlice<'a>>, Error>>
1321 where
1322 K: AsRef<[u8]>,
1323 I: IntoIterator<Item = (&'b W, K)>,
1324 W: 'b + AsColumnFamilyRef,
1325 {
1326 keys.into_iter()
1327 .map(|(cf, k)| self.get_pinned_cf_opt(cf, k, readopts))
1328 .collect()
1329 }
1330
1331 pub fn multi_get_cf<'a, 'b: 'a, K, I, W>(
1333 &'a self,
1334 keys: I,
1335 ) -> Vec<Result<Option<Vec<u8>>, Error>>
1336 where
1337 K: AsRef<[u8]>,
1338 I: IntoIterator<Item = (&'b W, K)>,
1339 W: 'b + AsColumnFamilyRef,
1340 {
1341 DEFAULT_READ_OPTS.with(|opts| self.multi_get_cf_opt(keys, opts))
1342 }
1343
1344 pub fn multi_get_cf_opt<'a, 'b: 'a, K, I, W>(
1346 &'a self,
1347 keys: I,
1348 readopts: &ReadOptions,
1349 ) -> Vec<Result<Option<Vec<u8>>, Error>>
1350 where
1351 K: AsRef<[u8]>,
1352 I: IntoIterator<Item = (&'b W, K)>,
1353 W: 'b + AsColumnFamilyRef,
1354 {
1355 let cfs_and_owned_keys: Vec<(&'b W, K)> = keys.into_iter().collect();
1356 let keys_sizes: Vec<usize> = cfs_and_owned_keys
1357 .iter()
1358 .map(|(_, k)| k.as_ref().len())
1359 .collect();
1360 let ptr_keys: Vec<*const c_char> = cfs_and_owned_keys
1361 .iter()
1362 .map(|(_, k)| k.as_ref().as_ptr() as *const c_char)
1363 .collect();
1364 let ptr_cfs: Vec<*const ffi::rocksdb_column_family_handle_t> = cfs_and_owned_keys
1365 .iter()
1366 .map(|(c, _)| c.inner().cast_const())
1367 .collect();
1368 let mut values: Vec<*mut c_char> = Vec::with_capacity(ptr_keys.len());
1369 let mut values_sizes: Vec<usize> = Vec::with_capacity(ptr_keys.len());
1370 let mut errors: Vec<*mut c_char> = Vec::with_capacity(ptr_keys.len());
1371 unsafe {
1372 ffi::rocksdb_multi_get_cf(
1373 self.inner.inner(),
1374 readopts.inner,
1375 ptr_cfs.as_ptr(),
1376 ptr_keys.len(),
1377 ptr_keys.as_ptr(),
1378 keys_sizes.as_ptr(),
1379 values.as_mut_ptr(),
1380 values_sizes.as_mut_ptr(),
1381 errors.as_mut_ptr(),
1382 );
1383 }
1384
1385 unsafe {
1386 values.set_len(ptr_keys.len());
1387 values_sizes.set_len(ptr_keys.len());
1388 errors.set_len(ptr_keys.len());
1389 }
1390
1391 convert_values(values, values_sizes, errors)
1392 }
1393
1394 pub fn batched_multi_get_cf<'a, K, I>(
1398 &'_ self,
1399 cf: &impl AsColumnFamilyRef,
1400 keys: I,
1401 sorted_input: bool,
1402 ) -> Vec<Result<Option<DBPinnableSlice<'_>>, Error>>
1403 where
1404 K: AsRef<[u8]> + 'a + ?Sized,
1405 I: IntoIterator<Item = &'a K>,
1406 {
1407 DEFAULT_READ_OPTS.with(|opts| self.batched_multi_get_cf_opt(cf, keys, sorted_input, opts))
1408 }
1409
1410 pub fn batched_multi_get_cf_opt<'a, K, I>(
1414 &'_ self,
1415 cf: &impl AsColumnFamilyRef,
1416 keys: I,
1417 sorted_input: bool,
1418 readopts: &ReadOptions,
1419 ) -> Vec<Result<Option<DBPinnableSlice<'_>>, Error>>
1420 where
1421 K: AsRef<[u8]> + 'a + ?Sized,
1422 I: IntoIterator<Item = &'a K>,
1423 {
1424 let (ptr_keys, keys_sizes): (Vec<_>, Vec<_>) = keys
1425 .into_iter()
1426 .map(|k| {
1427 let k = k.as_ref();
1428 (k.as_ptr() as *const c_char, k.len())
1429 })
1430 .unzip();
1431
1432 let mut pinned_values = vec![ptr::null_mut(); ptr_keys.len()];
1433 let mut errors = vec![ptr::null_mut(); ptr_keys.len()];
1434
1435 unsafe {
1436 ffi::rocksdb_batched_multi_get_cf(
1437 self.inner.inner(),
1438 readopts.inner,
1439 cf.inner(),
1440 ptr_keys.len(),
1441 ptr_keys.as_ptr(),
1442 keys_sizes.as_ptr(),
1443 pinned_values.as_mut_ptr(),
1444 errors.as_mut_ptr(),
1445 sorted_input,
1446 );
1447 pinned_values
1448 .into_iter()
1449 .zip(errors)
1450 .map(|(v, e)| {
1451 if e.is_null() {
1452 if v.is_null() {
1453 Ok(None)
1454 } else {
1455 Ok(Some(DBPinnableSlice::from_c(v)))
1456 }
1457 } else {
1458 Err(Error::new(crate::ffi_util::error_message(e)))
1459 }
1460 })
1461 .collect()
1462 }
1463 }
1464
1465 pub fn key_may_exist<K: AsRef<[u8]>>(&self, key: K) -> bool {
1468 DEFAULT_READ_OPTS.with(|opts| self.key_may_exist_opt(key, opts))
1469 }
1470
1471 pub fn key_may_exist_opt<K: AsRef<[u8]>>(&self, key: K, readopts: &ReadOptions) -> bool {
1474 let key = key.as_ref();
1475 unsafe {
1476 0 != ffi::rocksdb_key_may_exist(
1477 self.inner.inner(),
1478 readopts.inner,
1479 key.as_ptr() as *const c_char,
1480 key.len() as size_t,
1481 ptr::null_mut(), ptr::null_mut(), ptr::null(), 0, ptr::null_mut(), )
1487 }
1488 }
1489
1490 pub fn key_may_exist_cf<K: AsRef<[u8]>>(&self, cf: &impl AsColumnFamilyRef, key: K) -> bool {
1493 DEFAULT_READ_OPTS.with(|opts| self.key_may_exist_cf_opt(cf, key, opts))
1494 }
1495
1496 pub fn key_may_exist_cf_opt<K: AsRef<[u8]>>(
1499 &self,
1500 cf: &impl AsColumnFamilyRef,
1501 key: K,
1502 readopts: &ReadOptions,
1503 ) -> bool {
1504 let key = key.as_ref();
1505 0 != unsafe {
1506 ffi::rocksdb_key_may_exist_cf(
1507 self.inner.inner(),
1508 readopts.inner,
1509 cf.inner(),
1510 key.as_ptr() as *const c_char,
1511 key.len() as size_t,
1512 ptr::null_mut(), ptr::null_mut(), ptr::null(), 0, ptr::null_mut(), )
1518 }
1519 }
1520
1521 pub fn key_may_exist_cf_opt_value<K: AsRef<[u8]>>(
1528 &self,
1529 cf: &impl AsColumnFamilyRef,
1530 key: K,
1531 readopts: &ReadOptions,
1532 ) -> (bool, Option<CSlice>) {
1533 let key = key.as_ref();
1534 let mut val: *mut c_char = ptr::null_mut();
1535 let mut val_len: usize = 0;
1536 let mut value_found: c_uchar = 0;
1537 let may_exists = 0
1538 != unsafe {
1539 ffi::rocksdb_key_may_exist_cf(
1540 self.inner.inner(),
1541 readopts.inner,
1542 cf.inner(),
1543 key.as_ptr() as *const c_char,
1544 key.len() as size_t,
1545 &mut val, &mut val_len, ptr::null(), 0, &mut value_found, )
1551 };
1552 if may_exists && value_found != 0 {
1555 (
1556 may_exists,
1557 Some(unsafe { CSlice::from_raw_parts(val, val_len) }),
1558 )
1559 } else {
1560 (may_exists, None)
1561 }
1562 }
1563
1564 fn create_inner_cf_handle(
1565 &self,
1566 name: impl CStrLike,
1567 opts: &Options,
1568 ) -> Result<*mut ffi::rocksdb_column_family_handle_t, Error> {
1569 let cf_name = name.bake().map_err(|err| {
1570 Error::new(format!(
1571 "Failed to convert path to CString when creating cf: {err}"
1572 ))
1573 })?;
1574 Ok(unsafe {
1575 ffi_try!(ffi::rocksdb_create_column_family(
1576 self.inner.inner(),
1577 opts.inner,
1578 cf_name.as_ptr(),
1579 ))
1580 })
1581 }
1582
1583 pub fn iterator<'a: 'b, 'b>(
1584 &'a self,
1585 mode: IteratorMode,
1586 ) -> DBIteratorWithThreadMode<'b, Self> {
1587 let readopts = ReadOptions::default();
1588 self.iterator_opt(mode, readopts)
1589 }
1590
1591 pub fn iterator_opt<'a: 'b, 'b>(
1592 &'a self,
1593 mode: IteratorMode,
1594 readopts: ReadOptions,
1595 ) -> DBIteratorWithThreadMode<'b, Self> {
1596 DBIteratorWithThreadMode::new(self, readopts, mode)
1597 }
1598
1599 pub fn iterator_cf_opt<'a: 'b, 'b>(
1602 &'a self,
1603 cf_handle: &impl AsColumnFamilyRef,
1604 readopts: ReadOptions,
1605 mode: IteratorMode,
1606 ) -> DBIteratorWithThreadMode<'b, Self> {
1607 DBIteratorWithThreadMode::new_cf(self, cf_handle.inner(), readopts, mode)
1608 }
1609
1610 pub fn full_iterator<'a: 'b, 'b>(
1614 &'a self,
1615 mode: IteratorMode,
1616 ) -> DBIteratorWithThreadMode<'b, Self> {
1617 let mut opts = ReadOptions::default();
1618 opts.set_total_order_seek(true);
1619 DBIteratorWithThreadMode::new(self, opts, mode)
1620 }
1621
1622 pub fn prefix_iterator<'a: 'b, 'b, P: AsRef<[u8]>>(
1623 &'a self,
1624 prefix: P,
1625 ) -> DBIteratorWithThreadMode<'b, Self> {
1626 let mut opts = ReadOptions::default();
1627 opts.set_prefix_same_as_start(true);
1628 DBIteratorWithThreadMode::new(
1629 self,
1630 opts,
1631 IteratorMode::From(prefix.as_ref(), Direction::Forward),
1632 )
1633 }
1634
1635 pub fn iterator_cf<'a: 'b, 'b>(
1636 &'a self,
1637 cf_handle: &impl AsColumnFamilyRef,
1638 mode: IteratorMode,
1639 ) -> DBIteratorWithThreadMode<'b, Self> {
1640 let opts = ReadOptions::default();
1641 DBIteratorWithThreadMode::new_cf(self, cf_handle.inner(), opts, mode)
1642 }
1643
1644 pub fn full_iterator_cf<'a: 'b, 'b>(
1645 &'a self,
1646 cf_handle: &impl AsColumnFamilyRef,
1647 mode: IteratorMode,
1648 ) -> DBIteratorWithThreadMode<'b, Self> {
1649 let mut opts = ReadOptions::default();
1650 opts.set_total_order_seek(true);
1651 DBIteratorWithThreadMode::new_cf(self, cf_handle.inner(), opts, mode)
1652 }
1653
1654 pub fn prefix_iterator_cf<'a, P: AsRef<[u8]>>(
1655 &'a self,
1656 cf_handle: &impl AsColumnFamilyRef,
1657 prefix: P,
1658 ) -> DBIteratorWithThreadMode<'a, Self> {
1659 let mut opts = ReadOptions::default();
1660 opts.set_prefix_same_as_start(true);
1661 DBIteratorWithThreadMode::<'a, Self>::new_cf(
1662 self,
1663 cf_handle.inner(),
1664 opts,
1665 IteratorMode::From(prefix.as_ref(), Direction::Forward),
1666 )
1667 }
1668
1669 pub fn prefix_exists<P: AsRef<[u8]>>(&self, prefix: P) -> Result<bool, Error> {
1676 let p = prefix.as_ref();
1677 PREFIX_READ_OPTS.with(|rc| {
1678 let mut opts = rc.borrow_mut();
1679 opts.set_iterate_range(crate::PrefixRange(p));
1680 self.prefix_exists_opt(p, &opts)
1681 })
1682 }
1683
1684 pub fn prefix_exists_opt<P: AsRef<[u8]>>(
1687 &self,
1688 prefix: P,
1689 readopts: &ReadOptions,
1690 ) -> Result<bool, Error> {
1691 let prefix = prefix.as_ref();
1692 let iter = unsafe { self.create_iterator(readopts) };
1693 let res = unsafe {
1694 ffi::rocksdb_iter_seek(
1695 iter,
1696 prefix.as_ptr() as *const c_char,
1697 prefix.len() as size_t,
1698 );
1699 if ffi::rocksdb_iter_valid(iter) != 0 {
1700 let mut key_len: size_t = 0;
1701 let key_ptr = ffi::rocksdb_iter_key(iter, &mut key_len);
1702 let key = slice::from_raw_parts(key_ptr as *const u8, key_len as usize);
1703 Ok(key.starts_with(prefix))
1704 } else if let Err(e) = (|| {
1705 ffi_try!(ffi::rocksdb_iter_get_error(iter));
1707 Ok::<(), Error>(())
1708 })() {
1709 Err(e)
1710 } else {
1711 Ok(false)
1712 }
1713 };
1714 unsafe { ffi::rocksdb_iter_destroy(iter) };
1715 res
1716 }
1717
1718 pub fn prefix_prober(&self) -> PrefixProber<'_, Self> {
1726 let mut opts = ReadOptions::default();
1727 opts.set_prefix_same_as_start(true);
1728 PrefixProber {
1729 raw: DBRawIteratorWithThreadMode::new(self, opts),
1730 }
1731 }
1732
1733 pub fn prefix_prober_with_opts(&self, readopts: ReadOptions) -> PrefixProber<'_, Self> {
1740 PrefixProber {
1741 raw: DBRawIteratorWithThreadMode::new(self, readopts),
1742 }
1743 }
1744
1745 pub fn prefix_prober_cf(&self, cf_handle: &impl AsColumnFamilyRef) -> PrefixProber<'_, Self> {
1748 let mut opts = ReadOptions::default();
1749 opts.set_prefix_same_as_start(true);
1750 PrefixProber {
1751 raw: DBRawIteratorWithThreadMode::new_cf(self, cf_handle.inner(), opts),
1752 }
1753 }
1754
1755 pub fn prefix_prober_cf_with_opts(
1760 &self,
1761 cf_handle: &impl AsColumnFamilyRef,
1762 readopts: ReadOptions,
1763 ) -> PrefixProber<'_, Self> {
1764 PrefixProber {
1765 raw: DBRawIteratorWithThreadMode::new_cf(self, cf_handle.inner(), readopts),
1766 }
1767 }
1768
1769 pub fn prefix_exists_cf<P: AsRef<[u8]>>(
1775 &self,
1776 cf_handle: &impl AsColumnFamilyRef,
1777 prefix: P,
1778 ) -> Result<bool, Error> {
1779 let p = prefix.as_ref();
1780 PREFIX_READ_OPTS.with(|rc| {
1781 let mut opts = rc.borrow_mut();
1782 opts.set_iterate_range(crate::PrefixRange(p));
1783 self.prefix_exists_cf_opt(cf_handle, p, &opts)
1784 })
1785 }
1786
1787 pub fn prefix_exists_cf_opt<P: AsRef<[u8]>>(
1790 &self,
1791 cf_handle: &impl AsColumnFamilyRef,
1792 prefix: P,
1793 readopts: &ReadOptions,
1794 ) -> Result<bool, Error> {
1795 let prefix = prefix.as_ref();
1796 let iter = unsafe { self.create_iterator_cf(cf_handle.inner(), readopts) };
1797 let res = unsafe {
1798 ffi::rocksdb_iter_seek(
1799 iter,
1800 prefix.as_ptr() as *const c_char,
1801 prefix.len() as size_t,
1802 );
1803 if ffi::rocksdb_iter_valid(iter) != 0 {
1804 let mut key_len: size_t = 0;
1805 let key_ptr = ffi::rocksdb_iter_key(iter, &mut key_len);
1806 let key = slice::from_raw_parts(key_ptr as *const u8, key_len as usize);
1807 Ok(key.starts_with(prefix))
1808 } else if let Err(e) = (|| {
1809 ffi_try!(ffi::rocksdb_iter_get_error(iter));
1810 Ok::<(), Error>(())
1811 })() {
1812 Err(e)
1813 } else {
1814 Ok(false)
1815 }
1816 };
1817 unsafe { ffi::rocksdb_iter_destroy(iter) };
1818 res
1819 }
1820
1821 pub fn raw_iterator<'a: 'b, 'b>(&'a self) -> DBRawIteratorWithThreadMode<'b, Self> {
1823 let opts = ReadOptions::default();
1824 DBRawIteratorWithThreadMode::new(self, opts)
1825 }
1826
1827 pub fn raw_iterator_cf<'a: 'b, 'b>(
1829 &'a self,
1830 cf_handle: &impl AsColumnFamilyRef,
1831 ) -> DBRawIteratorWithThreadMode<'b, Self> {
1832 let opts = ReadOptions::default();
1833 DBRawIteratorWithThreadMode::new_cf(self, cf_handle.inner(), opts)
1834 }
1835
1836 pub fn raw_iterator_opt<'a: 'b, 'b>(
1838 &'a self,
1839 readopts: ReadOptions,
1840 ) -> DBRawIteratorWithThreadMode<'b, Self> {
1841 DBRawIteratorWithThreadMode::new(self, readopts)
1842 }
1843
1844 pub fn raw_iterator_cf_opt<'a: 'b, 'b>(
1846 &'a self,
1847 cf_handle: &impl AsColumnFamilyRef,
1848 readopts: ReadOptions,
1849 ) -> DBRawIteratorWithThreadMode<'b, Self> {
1850 DBRawIteratorWithThreadMode::new_cf(self, cf_handle.inner(), readopts)
1851 }
1852
1853 pub fn snapshot(&'_ self) -> SnapshotWithThreadMode<'_, Self> {
1854 SnapshotWithThreadMode::<Self>::new(self)
1855 }
1856
1857 pub fn put_opt<K, V>(&self, key: K, value: V, writeopts: &WriteOptions) -> Result<(), Error>
1858 where
1859 K: AsRef<[u8]>,
1860 V: AsRef<[u8]>,
1861 {
1862 let key = key.as_ref();
1863 let value = value.as_ref();
1864
1865 unsafe {
1866 ffi_try!(ffi::rocksdb_put(
1867 self.inner.inner(),
1868 writeopts.inner,
1869 key.as_ptr() as *const c_char,
1870 key.len() as size_t,
1871 value.as_ptr() as *const c_char,
1872 value.len() as size_t,
1873 ));
1874 Ok(())
1875 }
1876 }
1877
1878 pub fn put_cf_opt<K, V>(
1879 &self,
1880 cf: &impl AsColumnFamilyRef,
1881 key: K,
1882 value: V,
1883 writeopts: &WriteOptions,
1884 ) -> Result<(), Error>
1885 where
1886 K: AsRef<[u8]>,
1887 V: AsRef<[u8]>,
1888 {
1889 let key = key.as_ref();
1890 let value = value.as_ref();
1891
1892 unsafe {
1893 ffi_try!(ffi::rocksdb_put_cf(
1894 self.inner.inner(),
1895 writeopts.inner,
1896 cf.inner(),
1897 key.as_ptr() as *const c_char,
1898 key.len() as size_t,
1899 value.as_ptr() as *const c_char,
1900 value.len() as size_t,
1901 ));
1902 Ok(())
1903 }
1904 }
1905
1906 pub fn put_with_ts_opt<K, V, S>(
1913 &self,
1914 key: K,
1915 ts: S,
1916 value: V,
1917 writeopts: &WriteOptions,
1918 ) -> Result<(), Error>
1919 where
1920 K: AsRef<[u8]>,
1921 V: AsRef<[u8]>,
1922 S: AsRef<[u8]>,
1923 {
1924 let key = key.as_ref();
1925 let value = value.as_ref();
1926 let ts = ts.as_ref();
1927 unsafe {
1928 ffi_try!(ffi::rocksdb_put_with_ts(
1929 self.inner.inner(),
1930 writeopts.inner,
1931 key.as_ptr() as *const c_char,
1932 key.len() as size_t,
1933 ts.as_ptr() as *const c_char,
1934 ts.len() as size_t,
1935 value.as_ptr() as *const c_char,
1936 value.len() as size_t,
1937 ));
1938 Ok(())
1939 }
1940 }
1941
1942 pub fn put_cf_with_ts_opt<K, V, S>(
1949 &self,
1950 cf: &impl AsColumnFamilyRef,
1951 key: K,
1952 ts: S,
1953 value: V,
1954 writeopts: &WriteOptions,
1955 ) -> Result<(), Error>
1956 where
1957 K: AsRef<[u8]>,
1958 V: AsRef<[u8]>,
1959 S: AsRef<[u8]>,
1960 {
1961 let key = key.as_ref();
1962 let value = value.as_ref();
1963 let ts = ts.as_ref();
1964 unsafe {
1965 ffi_try!(ffi::rocksdb_put_cf_with_ts(
1966 self.inner.inner(),
1967 writeopts.inner,
1968 cf.inner(),
1969 key.as_ptr() as *const c_char,
1970 key.len() as size_t,
1971 ts.as_ptr() as *const c_char,
1972 ts.len() as size_t,
1973 value.as_ptr() as *const c_char,
1974 value.len() as size_t,
1975 ));
1976 Ok(())
1977 }
1978 }
1979
1980 pub fn merge_opt<K, V>(&self, key: K, value: V, writeopts: &WriteOptions) -> Result<(), Error>
1981 where
1982 K: AsRef<[u8]>,
1983 V: AsRef<[u8]>,
1984 {
1985 let key = key.as_ref();
1986 let value = value.as_ref();
1987
1988 unsafe {
1989 ffi_try!(ffi::rocksdb_merge(
1990 self.inner.inner(),
1991 writeopts.inner,
1992 key.as_ptr() as *const c_char,
1993 key.len() as size_t,
1994 value.as_ptr() as *const c_char,
1995 value.len() as size_t,
1996 ));
1997 Ok(())
1998 }
1999 }
2000
2001 pub fn merge_cf_opt<K, V>(
2002 &self,
2003 cf: &impl AsColumnFamilyRef,
2004 key: K,
2005 value: V,
2006 writeopts: &WriteOptions,
2007 ) -> Result<(), Error>
2008 where
2009 K: AsRef<[u8]>,
2010 V: AsRef<[u8]>,
2011 {
2012 let key = key.as_ref();
2013 let value = value.as_ref();
2014
2015 unsafe {
2016 ffi_try!(ffi::rocksdb_merge_cf(
2017 self.inner.inner(),
2018 writeopts.inner,
2019 cf.inner(),
2020 key.as_ptr() as *const c_char,
2021 key.len() as size_t,
2022 value.as_ptr() as *const c_char,
2023 value.len() as size_t,
2024 ));
2025 Ok(())
2026 }
2027 }
2028
2029 pub fn delete_opt<K: AsRef<[u8]>>(
2030 &self,
2031 key: K,
2032 writeopts: &WriteOptions,
2033 ) -> Result<(), Error> {
2034 let key = key.as_ref();
2035
2036 unsafe {
2037 ffi_try!(ffi::rocksdb_delete(
2038 self.inner.inner(),
2039 writeopts.inner,
2040 key.as_ptr() as *const c_char,
2041 key.len() as size_t,
2042 ));
2043 Ok(())
2044 }
2045 }
2046
2047 pub fn delete_cf_opt<K: AsRef<[u8]>>(
2048 &self,
2049 cf: &impl AsColumnFamilyRef,
2050 key: K,
2051 writeopts: &WriteOptions,
2052 ) -> Result<(), Error> {
2053 let key = key.as_ref();
2054
2055 unsafe {
2056 ffi_try!(ffi::rocksdb_delete_cf(
2057 self.inner.inner(),
2058 writeopts.inner,
2059 cf.inner(),
2060 key.as_ptr() as *const c_char,
2061 key.len() as size_t,
2062 ));
2063 Ok(())
2064 }
2065 }
2066
2067 pub fn delete_with_ts_opt<K, S>(
2071 &self,
2072 key: K,
2073 ts: S,
2074 writeopts: &WriteOptions,
2075 ) -> Result<(), Error>
2076 where
2077 K: AsRef<[u8]>,
2078 S: AsRef<[u8]>,
2079 {
2080 let key = key.as_ref();
2081 let ts = ts.as_ref();
2082 unsafe {
2083 ffi_try!(ffi::rocksdb_delete_with_ts(
2084 self.inner.inner(),
2085 writeopts.inner,
2086 key.as_ptr() as *const c_char,
2087 key.len() as size_t,
2088 ts.as_ptr() as *const c_char,
2089 ts.len() as size_t,
2090 ));
2091 Ok(())
2092 }
2093 }
2094
2095 pub fn delete_cf_with_ts_opt<K, S>(
2099 &self,
2100 cf: &impl AsColumnFamilyRef,
2101 key: K,
2102 ts: S,
2103 writeopts: &WriteOptions,
2104 ) -> Result<(), Error>
2105 where
2106 K: AsRef<[u8]>,
2107 S: AsRef<[u8]>,
2108 {
2109 let key = key.as_ref();
2110 let ts = ts.as_ref();
2111 unsafe {
2112 ffi_try!(ffi::rocksdb_delete_cf_with_ts(
2113 self.inner.inner(),
2114 writeopts.inner,
2115 cf.inner(),
2116 key.as_ptr() as *const c_char,
2117 key.len() as size_t,
2118 ts.as_ptr() as *const c_char,
2119 ts.len() as size_t,
2120 ));
2121 Ok(())
2122 }
2123 }
2124
2125 pub fn put<K, V>(&self, key: K, value: V) -> Result<(), Error>
2126 where
2127 K: AsRef<[u8]>,
2128 V: AsRef<[u8]>,
2129 {
2130 DEFAULT_WRITE_OPTS.with(|opts| self.put_opt(key, value, opts))
2131 }
2132
2133 pub fn put_cf<K, V>(&self, cf: &impl AsColumnFamilyRef, key: K, value: V) -> Result<(), Error>
2134 where
2135 K: AsRef<[u8]>,
2136 V: AsRef<[u8]>,
2137 {
2138 DEFAULT_WRITE_OPTS.with(|opts| self.put_cf_opt(cf, key, value, opts))
2139 }
2140
2141 pub fn put_with_ts<K, V, S>(&self, key: K, ts: S, value: V) -> Result<(), Error>
2148 where
2149 K: AsRef<[u8]>,
2150 V: AsRef<[u8]>,
2151 S: AsRef<[u8]>,
2152 {
2153 DEFAULT_WRITE_OPTS
2154 .with(|opts| self.put_with_ts_opt(key.as_ref(), ts.as_ref(), value.as_ref(), opts))
2155 }
2156
2157 pub fn put_cf_with_ts<K, V, S>(
2164 &self,
2165 cf: &impl AsColumnFamilyRef,
2166 key: K,
2167 ts: S,
2168 value: V,
2169 ) -> Result<(), Error>
2170 where
2171 K: AsRef<[u8]>,
2172 V: AsRef<[u8]>,
2173 S: AsRef<[u8]>,
2174 {
2175 DEFAULT_WRITE_OPTS.with(|opts| {
2176 self.put_cf_with_ts_opt(cf, key.as_ref(), ts.as_ref(), value.as_ref(), opts)
2177 })
2178 }
2179
2180 pub fn merge<K, V>(&self, key: K, value: V) -> Result<(), Error>
2181 where
2182 K: AsRef<[u8]>,
2183 V: AsRef<[u8]>,
2184 {
2185 DEFAULT_WRITE_OPTS.with(|opts| self.merge_opt(key, value, opts))
2186 }
2187
2188 pub fn merge_cf<K, V>(&self, cf: &impl AsColumnFamilyRef, key: K, value: V) -> Result<(), Error>
2189 where
2190 K: AsRef<[u8]>,
2191 V: AsRef<[u8]>,
2192 {
2193 DEFAULT_WRITE_OPTS.with(|opts| self.merge_cf_opt(cf, key, value, opts))
2194 }
2195
2196 pub fn delete<K: AsRef<[u8]>>(&self, key: K) -> Result<(), Error> {
2197 DEFAULT_WRITE_OPTS.with(|opts| self.delete_opt(key, opts))
2198 }
2199
2200 pub fn delete_cf<K: AsRef<[u8]>>(
2201 &self,
2202 cf: &impl AsColumnFamilyRef,
2203 key: K,
2204 ) -> Result<(), Error> {
2205 DEFAULT_WRITE_OPTS.with(|opts| self.delete_cf_opt(cf, key, opts))
2206 }
2207
2208 pub fn delete_with_ts<K: AsRef<[u8]>, S: AsRef<[u8]>>(
2212 &self,
2213 key: K,
2214 ts: S,
2215 ) -> Result<(), Error> {
2216 DEFAULT_WRITE_OPTS.with(|opts| self.delete_with_ts_opt(key, ts, opts))
2217 }
2218
2219 pub fn delete_cf_with_ts<K: AsRef<[u8]>, S: AsRef<[u8]>>(
2223 &self,
2224 cf: &impl AsColumnFamilyRef,
2225 key: K,
2226 ts: S,
2227 ) -> Result<(), Error> {
2228 DEFAULT_WRITE_OPTS.with(|opts| self.delete_cf_with_ts_opt(cf, key, ts, opts))
2229 }
2230
2231 pub fn single_delete_opt<K: AsRef<[u8]>>(
2251 &self,
2252 key: K,
2253 writeopts: &WriteOptions,
2254 ) -> Result<(), Error> {
2255 let key = key.as_ref();
2256
2257 unsafe {
2258 ffi_try!(ffi::rocksdb_singledelete(
2259 self.inner.inner(),
2260 writeopts.inner,
2261 key.as_ptr() as *const c_char,
2262 key.len() as size_t,
2263 ));
2264 Ok(())
2265 }
2266 }
2267
2268 pub fn single_delete_cf_opt<K: AsRef<[u8]>>(
2272 &self,
2273 cf: &impl AsColumnFamilyRef,
2274 key: K,
2275 writeopts: &WriteOptions,
2276 ) -> Result<(), Error> {
2277 let key = key.as_ref();
2278
2279 unsafe {
2280 ffi_try!(ffi::rocksdb_singledelete_cf(
2281 self.inner.inner(),
2282 writeopts.inner,
2283 cf.inner(),
2284 key.as_ptr() as *const c_char,
2285 key.len() as size_t,
2286 ));
2287 Ok(())
2288 }
2289 }
2290
2291 pub fn single_delete_with_ts_opt<K, S>(
2298 &self,
2299 key: K,
2300 ts: S,
2301 writeopts: &WriteOptions,
2302 ) -> Result<(), Error>
2303 where
2304 K: AsRef<[u8]>,
2305 S: AsRef<[u8]>,
2306 {
2307 let key = key.as_ref();
2308 let ts = ts.as_ref();
2309 unsafe {
2310 ffi_try!(ffi::rocksdb_singledelete_with_ts(
2311 self.inner.inner(),
2312 writeopts.inner,
2313 key.as_ptr() as *const c_char,
2314 key.len() as size_t,
2315 ts.as_ptr() as *const c_char,
2316 ts.len() as size_t,
2317 ));
2318 Ok(())
2319 }
2320 }
2321
2322 pub fn single_delete_cf_with_ts_opt<K, S>(
2329 &self,
2330 cf: &impl AsColumnFamilyRef,
2331 key: K,
2332 ts: S,
2333 writeopts: &WriteOptions,
2334 ) -> Result<(), Error>
2335 where
2336 K: AsRef<[u8]>,
2337 S: AsRef<[u8]>,
2338 {
2339 let key = key.as_ref();
2340 let ts = ts.as_ref();
2341 unsafe {
2342 ffi_try!(ffi::rocksdb_singledelete_cf_with_ts(
2343 self.inner.inner(),
2344 writeopts.inner,
2345 cf.inner(),
2346 key.as_ptr() as *const c_char,
2347 key.len() as size_t,
2348 ts.as_ptr() as *const c_char,
2349 ts.len() as size_t,
2350 ));
2351 Ok(())
2352 }
2353 }
2354
2355 pub fn single_delete<K: AsRef<[u8]>>(&self, key: K) -> Result<(), Error> {
2359 DEFAULT_WRITE_OPTS.with(|opts| self.single_delete_opt(key, opts))
2360 }
2361
2362 pub fn single_delete_cf<K: AsRef<[u8]>>(
2366 &self,
2367 cf: &impl AsColumnFamilyRef,
2368 key: K,
2369 ) -> Result<(), Error> {
2370 DEFAULT_WRITE_OPTS.with(|opts| self.single_delete_cf_opt(cf, key, opts))
2371 }
2372
2373 pub fn single_delete_with_ts<K: AsRef<[u8]>, S: AsRef<[u8]>>(
2380 &self,
2381 key: K,
2382 ts: S,
2383 ) -> Result<(), Error> {
2384 DEFAULT_WRITE_OPTS.with(|opts| self.single_delete_with_ts_opt(key, ts, opts))
2385 }
2386
2387 pub fn single_delete_cf_with_ts<K: AsRef<[u8]>, S: AsRef<[u8]>>(
2394 &self,
2395 cf: &impl AsColumnFamilyRef,
2396 key: K,
2397 ts: S,
2398 ) -> Result<(), Error> {
2399 DEFAULT_WRITE_OPTS.with(|opts| self.single_delete_cf_with_ts_opt(cf, key, ts, opts))
2400 }
2401
2402 pub fn compact_range<S: AsRef<[u8]>, E: AsRef<[u8]>>(&self, start: Option<S>, end: Option<E>) {
2404 unsafe {
2405 let start = start.as_ref().map(AsRef::as_ref);
2406 let end = end.as_ref().map(AsRef::as_ref);
2407
2408 ffi::rocksdb_compact_range(
2409 self.inner.inner(),
2410 opt_bytes_to_ptr(start),
2411 start.map_or(0, <[u8]>::len) as size_t,
2412 opt_bytes_to_ptr(end),
2413 end.map_or(0, <[u8]>::len) as size_t,
2414 );
2415 }
2416 }
2417
2418 pub fn compact_range_opt<S: AsRef<[u8]>, E: AsRef<[u8]>>(
2420 &self,
2421 start: Option<S>,
2422 end: Option<E>,
2423 opts: &CompactOptions,
2424 ) {
2425 unsafe {
2426 let start = start.as_ref().map(AsRef::as_ref);
2427 let end = end.as_ref().map(AsRef::as_ref);
2428
2429 ffi::rocksdb_compact_range_opt(
2430 self.inner.inner(),
2431 opts.inner,
2432 opt_bytes_to_ptr(start),
2433 start.map_or(0, <[u8]>::len) as size_t,
2434 opt_bytes_to_ptr(end),
2435 end.map_or(0, <[u8]>::len) as size_t,
2436 );
2437 }
2438 }
2439
2440 pub fn compact_range_cf<S: AsRef<[u8]>, E: AsRef<[u8]>>(
2443 &self,
2444 cf: &impl AsColumnFamilyRef,
2445 start: Option<S>,
2446 end: Option<E>,
2447 ) {
2448 unsafe {
2449 let start = start.as_ref().map(AsRef::as_ref);
2450 let end = end.as_ref().map(AsRef::as_ref);
2451
2452 ffi::rocksdb_compact_range_cf(
2453 self.inner.inner(),
2454 cf.inner(),
2455 opt_bytes_to_ptr(start),
2456 start.map_or(0, <[u8]>::len) as size_t,
2457 opt_bytes_to_ptr(end),
2458 end.map_or(0, <[u8]>::len) as size_t,
2459 );
2460 }
2461 }
2462
2463 pub fn compact_range_cf_opt<S: AsRef<[u8]>, E: AsRef<[u8]>>(
2465 &self,
2466 cf: &impl AsColumnFamilyRef,
2467 start: Option<S>,
2468 end: Option<E>,
2469 opts: &CompactOptions,
2470 ) {
2471 unsafe {
2472 let start = start.as_ref().map(AsRef::as_ref);
2473 let end = end.as_ref().map(AsRef::as_ref);
2474
2475 ffi::rocksdb_compact_range_cf_opt(
2476 self.inner.inner(),
2477 cf.inner(),
2478 opts.inner,
2479 opt_bytes_to_ptr(start),
2480 start.map_or(0, <[u8]>::len) as size_t,
2481 opt_bytes_to_ptr(end),
2482 end.map_or(0, <[u8]>::len) as size_t,
2483 );
2484 }
2485 }
2486
2487 pub fn wait_for_compact(&self, opts: &WaitForCompactOptions) -> Result<(), Error> {
2496 unsafe {
2497 ffi_try!(ffi::rocksdb_wait_for_compact(
2498 self.inner.inner(),
2499 opts.inner
2500 ));
2501 }
2502 Ok(())
2503 }
2504
2505 pub fn set_options(&self, opts: &[(&str, &str)]) -> Result<(), Error> {
2506 let copts = convert_options(opts)?;
2507 let cnames: Vec<*const c_char> = copts.iter().map(|opt| opt.0.as_ptr()).collect();
2508 let cvalues: Vec<*const c_char> = copts.iter().map(|opt| opt.1.as_ptr()).collect();
2509 let count = opts.len() as i32;
2510 unsafe {
2511 ffi_try!(ffi::rocksdb_set_options(
2512 self.inner.inner(),
2513 count,
2514 cnames.as_ptr(),
2515 cvalues.as_ptr(),
2516 ));
2517 }
2518 Ok(())
2519 }
2520
2521 pub fn set_options_cf(
2522 &self,
2523 cf: &impl AsColumnFamilyRef,
2524 opts: &[(&str, &str)],
2525 ) -> Result<(), Error> {
2526 let copts = convert_options(opts)?;
2527 let cnames: Vec<*const c_char> = copts.iter().map(|opt| opt.0.as_ptr()).collect();
2528 let cvalues: Vec<*const c_char> = copts.iter().map(|opt| opt.1.as_ptr()).collect();
2529 let count = opts.len() as i32;
2530 unsafe {
2531 ffi_try!(ffi::rocksdb_set_options_cf(
2532 self.inner.inner(),
2533 cf.inner(),
2534 count,
2535 cnames.as_ptr(),
2536 cvalues.as_ptr(),
2537 ));
2538 }
2539 Ok(())
2540 }
2541
2542 fn property_value_impl<R>(
2551 name: impl CStrLike,
2552 get_property: impl FnOnce(*const c_char) -> *mut c_char,
2553 parse: impl FnOnce(&str) -> Result<R, Error>,
2554 ) -> Result<Option<R>, Error> {
2555 let value = match name.bake() {
2556 Ok(prop_name) => get_property(prop_name.as_ptr()),
2557 Err(e) => {
2558 return Err(Error::new(format!(
2559 "Failed to convert property name to CString: {e}"
2560 )));
2561 }
2562 };
2563 if value.is_null() {
2564 return Ok(None);
2565 }
2566 let result = match unsafe { CStr::from_ptr(value) }.to_str() {
2567 Ok(s) => parse(s).map(|value| Some(value)),
2568 Err(e) => Err(Error::new(format!(
2569 "Failed to convert property value to string: {e}"
2570 ))),
2571 };
2572 unsafe {
2573 ffi::rocksdb_free(value as *mut c_void);
2574 }
2575 result
2576 }
2577
2578 pub fn property_value(&self, name: impl CStrLike) -> Result<Option<String>, Error> {
2583 Self::property_value_impl(
2584 name,
2585 |prop_name| unsafe { ffi::rocksdb_property_value(self.inner.inner(), prop_name) },
2586 |str_value| Ok(str_value.to_owned()),
2587 )
2588 }
2589
2590 pub fn property_value_cf(
2595 &self,
2596 cf: &impl AsColumnFamilyRef,
2597 name: impl CStrLike,
2598 ) -> Result<Option<String>, Error> {
2599 Self::property_value_impl(
2600 name,
2601 |prop_name| unsafe {
2602 ffi::rocksdb_property_value_cf(self.inner.inner(), cf.inner(), prop_name)
2603 },
2604 |str_value| Ok(str_value.to_owned()),
2605 )
2606 }
2607
2608 fn parse_property_int_value(value: &str) -> Result<u64, Error> {
2609 value.parse::<u64>().map_err(|err| {
2610 Error::new(format!(
2611 "Failed to convert property value {value} to int: {err}"
2612 ))
2613 })
2614 }
2615
2616 pub fn property_int_value(&self, name: impl CStrLike) -> Result<Option<u64>, Error> {
2621 Self::property_value_impl(
2622 name,
2623 |prop_name| unsafe { ffi::rocksdb_property_value(self.inner.inner(), prop_name) },
2624 Self::parse_property_int_value,
2625 )
2626 }
2627
2628 pub fn property_int_value_cf(
2633 &self,
2634 cf: &impl AsColumnFamilyRef,
2635 name: impl CStrLike,
2636 ) -> Result<Option<u64>, Error> {
2637 Self::property_value_impl(
2638 name,
2639 |prop_name| unsafe {
2640 ffi::rocksdb_property_value_cf(self.inner.inner(), cf.inner(), prop_name)
2641 },
2642 Self::parse_property_int_value,
2643 )
2644 }
2645
2646 pub fn latest_sequence_number(&self) -> u64 {
2648 unsafe { ffi::rocksdb_get_latest_sequence_number(self.inner.inner()) }
2649 }
2650
2651 pub fn get_approximate_sizes(&self, ranges: &[Range]) -> Vec<u64> {
2659 self.get_approximate_sizes_cfopt(None::<&ColumnFamily>, ranges)
2660 }
2661
2662 pub fn get_approximate_sizes_cf(
2663 &self,
2664 cf: &impl AsColumnFamilyRef,
2665 ranges: &[Range],
2666 ) -> Vec<u64> {
2667 self.get_approximate_sizes_cfopt(Some(cf), ranges)
2668 }
2669
2670 fn get_approximate_sizes_cfopt(
2671 &self,
2672 cf: Option<&impl AsColumnFamilyRef>,
2673 ranges: &[Range],
2674 ) -> Vec<u64> {
2675 let start_keys: Vec<*const c_char> = ranges
2676 .iter()
2677 .map(|x| x.start_key.as_ptr() as *const c_char)
2678 .collect();
2679 let start_key_lens: Vec<_> = ranges.iter().map(|x| x.start_key.len()).collect();
2680 let end_keys: Vec<*const c_char> = ranges
2681 .iter()
2682 .map(|x| x.end_key.as_ptr() as *const c_char)
2683 .collect();
2684 let end_key_lens: Vec<_> = ranges.iter().map(|x| x.end_key.len()).collect();
2685 let mut sizes: Vec<u64> = vec![0; ranges.len()];
2686 let (n, start_key_ptr, start_key_len_ptr, end_key_ptr, end_key_len_ptr, size_ptr) = (
2687 ranges.len() as i32,
2688 start_keys.as_ptr(),
2689 start_key_lens.as_ptr(),
2690 end_keys.as_ptr(),
2691 end_key_lens.as_ptr(),
2692 sizes.as_mut_ptr(),
2693 );
2694 let mut err: *mut c_char = ptr::null_mut();
2695 match cf {
2696 None => unsafe {
2697 ffi::rocksdb_approximate_sizes(
2698 self.inner.inner(),
2699 n,
2700 start_key_ptr,
2701 start_key_len_ptr,
2702 end_key_ptr,
2703 end_key_len_ptr,
2704 size_ptr,
2705 &mut err,
2706 );
2707 },
2708 Some(cf) => unsafe {
2709 ffi::rocksdb_approximate_sizes_cf(
2710 self.inner.inner(),
2711 cf.inner(),
2712 n,
2713 start_key_ptr,
2714 start_key_len_ptr,
2715 end_key_ptr,
2716 end_key_len_ptr,
2717 size_ptr,
2718 &mut err,
2719 );
2720 },
2721 }
2722 sizes
2723 }
2724
2725 pub fn get_updates_since(&self, seq_number: u64) -> Result<DBWALIterator, Error> {
2736 unsafe {
2737 let opts: *const ffi::rocksdb_wal_readoptions_t = ptr::null();
2741 let iter = ffi_try!(ffi::rocksdb_get_updates_since(
2742 self.inner.inner(),
2743 seq_number,
2744 opts
2745 ));
2746 Ok(DBWALIterator {
2747 inner: iter,
2748 start_seq_number: seq_number,
2749 })
2750 }
2751 }
2752
2753 pub fn try_catch_up_with_primary(&self) -> Result<(), Error> {
2756 unsafe {
2757 ffi_try!(ffi::rocksdb_try_catch_up_with_primary(self.inner.inner()));
2758 }
2759 Ok(())
2760 }
2761
2762 pub fn ingest_external_file<P: AsRef<Path>>(&self, paths: Vec<P>) -> Result<(), Error> {
2764 let opts = IngestExternalFileOptions::default();
2765 self.ingest_external_file_opts(&opts, paths)
2766 }
2767
2768 pub fn ingest_external_file_opts<P: AsRef<Path>>(
2770 &self,
2771 opts: &IngestExternalFileOptions,
2772 paths: Vec<P>,
2773 ) -> Result<(), Error> {
2774 let paths_v: Vec<CString> = paths.iter().map(to_cpath).collect::<Result<Vec<_>, _>>()?;
2775 let cpaths: Vec<_> = paths_v.iter().map(|path| path.as_ptr()).collect();
2776
2777 self.ingest_external_file_raw(opts, &paths_v, &cpaths)
2778 }
2779
2780 pub fn ingest_external_file_cf<P: AsRef<Path>>(
2783 &self,
2784 cf: &impl AsColumnFamilyRef,
2785 paths: Vec<P>,
2786 ) -> Result<(), Error> {
2787 let opts = IngestExternalFileOptions::default();
2788 self.ingest_external_file_cf_opts(cf, &opts, paths)
2789 }
2790
2791 pub fn ingest_external_file_cf_opts<P: AsRef<Path>>(
2793 &self,
2794 cf: &impl AsColumnFamilyRef,
2795 opts: &IngestExternalFileOptions,
2796 paths: Vec<P>,
2797 ) -> Result<(), Error> {
2798 let paths_v: Vec<CString> = paths.iter().map(to_cpath).collect::<Result<Vec<_>, _>>()?;
2799 let cpaths: Vec<_> = paths_v.iter().map(|path| path.as_ptr()).collect();
2800
2801 self.ingest_external_file_raw_cf(cf, opts, &paths_v, &cpaths)
2802 }
2803
2804 fn ingest_external_file_raw(
2805 &self,
2806 opts: &IngestExternalFileOptions,
2807 paths_v: &[CString],
2808 cpaths: &[*const c_char],
2809 ) -> Result<(), Error> {
2810 unsafe {
2811 ffi_try!(ffi::rocksdb_ingest_external_file(
2812 self.inner.inner(),
2813 cpaths.as_ptr(),
2814 paths_v.len(),
2815 opts.inner.cast_const()
2816 ));
2817 Ok(())
2818 }
2819 }
2820
2821 fn ingest_external_file_raw_cf(
2822 &self,
2823 cf: &impl AsColumnFamilyRef,
2824 opts: &IngestExternalFileOptions,
2825 paths_v: &[CString],
2826 cpaths: &[*const c_char],
2827 ) -> Result<(), Error> {
2828 unsafe {
2829 ffi_try!(ffi::rocksdb_ingest_external_file_cf(
2830 self.inner.inner(),
2831 cf.inner(),
2832 cpaths.as_ptr(),
2833 paths_v.len(),
2834 opts.inner.cast_const()
2835 ));
2836 Ok(())
2837 }
2838 }
2839
2840 pub fn get_column_family_metadata(&self) -> ColumnFamilyMetaData {
2842 unsafe {
2843 let ptr = ffi::rocksdb_get_column_family_metadata(self.inner.inner());
2844
2845 let metadata = ColumnFamilyMetaData {
2846 size: ffi::rocksdb_column_family_metadata_get_size(ptr),
2847 name: from_cstr(ffi::rocksdb_column_family_metadata_get_name(ptr)),
2848 file_count: ffi::rocksdb_column_family_metadata_get_file_count(ptr),
2849 };
2850
2851 ffi::rocksdb_column_family_metadata_destroy(ptr);
2853
2854 metadata
2856 }
2857 }
2858
2859 pub fn get_column_family_metadata_cf(
2861 &self,
2862 cf: &impl AsColumnFamilyRef,
2863 ) -> ColumnFamilyMetaData {
2864 unsafe {
2865 let ptr = ffi::rocksdb_get_column_family_metadata_cf(self.inner.inner(), cf.inner());
2866
2867 let metadata = ColumnFamilyMetaData {
2868 size: ffi::rocksdb_column_family_metadata_get_size(ptr),
2869 name: from_cstr(ffi::rocksdb_column_family_metadata_get_name(ptr)),
2870 file_count: ffi::rocksdb_column_family_metadata_get_file_count(ptr),
2871 };
2872
2873 ffi::rocksdb_column_family_metadata_destroy(ptr);
2875
2876 metadata
2878 }
2879 }
2880
2881 pub fn live_files(&self) -> Result<Vec<LiveFile>, Error> {
2884 unsafe {
2885 let livefiles_ptr = ffi::rocksdb_livefiles(self.inner.inner());
2886 if livefiles_ptr.is_null() {
2887 Err(Error::new("Could not get live files".to_owned()))
2888 } else {
2889 let files = LiveFile::from_rocksdb_livefiles_ptr(livefiles_ptr);
2890
2891 ffi::rocksdb_livefiles_destroy(livefiles_ptr);
2893
2894 Ok(files)
2896 }
2897 }
2898 }
2899
2900 pub fn delete_file_in_range<K: AsRef<[u8]>>(&self, from: K, to: K) -> Result<(), Error> {
2909 let from = from.as_ref();
2910 let to = to.as_ref();
2911 unsafe {
2912 ffi_try!(ffi::rocksdb_delete_file_in_range(
2913 self.inner.inner(),
2914 from.as_ptr() as *const c_char,
2915 from.len() as size_t,
2916 to.as_ptr() as *const c_char,
2917 to.len() as size_t,
2918 ));
2919 Ok(())
2920 }
2921 }
2922
2923 pub fn delete_file_in_range_cf<K: AsRef<[u8]>>(
2925 &self,
2926 cf: &impl AsColumnFamilyRef,
2927 from: K,
2928 to: K,
2929 ) -> Result<(), Error> {
2930 let from = from.as_ref();
2931 let to = to.as_ref();
2932 unsafe {
2933 ffi_try!(ffi::rocksdb_delete_file_in_range_cf(
2934 self.inner.inner(),
2935 cf.inner(),
2936 from.as_ptr() as *const c_char,
2937 from.len() as size_t,
2938 to.as_ptr() as *const c_char,
2939 to.len() as size_t,
2940 ));
2941 Ok(())
2942 }
2943 }
2944
2945 pub fn cancel_all_background_work(&self, wait: bool) {
2947 unsafe {
2948 ffi::rocksdb_cancel_all_background_work(self.inner.inner(), c_uchar::from(wait));
2949 }
2950 }
2951
2952 fn drop_column_family<C>(
2953 &self,
2954 cf_inner: *mut ffi::rocksdb_column_family_handle_t,
2955 cf: C,
2956 ) -> Result<(), Error> {
2957 unsafe {
2958 ffi_try!(ffi::rocksdb_drop_column_family(
2960 self.inner.inner(),
2961 cf_inner
2962 ));
2963 }
2964 drop(cf);
2967 Ok(())
2968 }
2969
2970 pub fn increase_full_history_ts_low<S: AsRef<[u8]>>(
2975 &self,
2976 cf: &impl AsColumnFamilyRef,
2977 ts: S,
2978 ) -> Result<(), Error> {
2979 let ts = ts.as_ref();
2980 unsafe {
2981 ffi_try!(ffi::rocksdb_increase_full_history_ts_low(
2982 self.inner.inner(),
2983 cf.inner(),
2984 ts.as_ptr() as *const c_char,
2985 ts.len() as size_t,
2986 ));
2987 Ok(())
2988 }
2989 }
2990
2991 pub fn get_full_history_ts_low(&self, cf: &impl AsColumnFamilyRef) -> Result<Vec<u8>, Error> {
2993 unsafe {
2994 let mut ts_lowlen = 0;
2995 let ts = ffi_try!(ffi::rocksdb_get_full_history_ts_low(
2996 self.inner.inner(),
2997 cf.inner(),
2998 &mut ts_lowlen,
2999 ));
3000
3001 if ts.is_null() {
3002 Err(Error::new("Could not get full_history_ts_low".to_owned()))
3003 } else {
3004 let mut vec = vec![0; ts_lowlen];
3005 ptr::copy_nonoverlapping(ts as *mut u8, vec.as_mut_ptr(), ts_lowlen);
3006 ffi::rocksdb_free(ts as *mut c_void);
3007 Ok(vec)
3008 }
3009 }
3010 }
3011
3012 pub fn get_db_identity(&self) -> Result<Vec<u8>, Error> {
3014 unsafe {
3015 let mut length: usize = 0;
3016 let identity_ptr = ffi::rocksdb_get_db_identity(self.inner.inner(), &mut length);
3017 let identity_vec = raw_data(identity_ptr, length);
3018 ffi::rocksdb_free(identity_ptr as *mut c_void);
3019 identity_vec.ok_or_else(|| Error::new("get_db_identity returned NULL".to_string()))
3022 }
3023 }
3024}
3025
3026impl<I: DBInner> DBCommon<SingleThreaded, I> {
3027 pub fn create_cf<N: AsRef<str>>(&mut self, name: N, opts: &Options) -> Result<(), Error> {
3029 let inner = self.create_inner_cf_handle(name.as_ref(), opts)?;
3030 self.cfs
3031 .cfs
3032 .insert(name.as_ref().to_string(), ColumnFamily { inner });
3033 Ok(())
3034 }
3035
3036 #[doc = include_str!("db_create_column_family_with_import.md")]
3037 pub fn create_column_family_with_import<N: AsRef<str>>(
3038 &mut self,
3039 options: &Options,
3040 column_family_name: N,
3041 import_options: &ImportColumnFamilyOptions,
3042 metadata: &ExportImportFilesMetaData,
3043 ) -> Result<(), Error> {
3044 let name = column_family_name.as_ref();
3045 let c_name = CString::new(name).map_err(|err| {
3046 Error::new(format!(
3047 "Failed to convert name to CString while importing column family: {err}"
3048 ))
3049 })?;
3050 let inner = unsafe {
3051 ffi_try!(ffi::rocksdb_create_column_family_with_import(
3052 self.inner.inner(),
3053 options.inner,
3054 c_name.as_ptr(),
3055 import_options.inner,
3056 metadata.inner
3057 ))
3058 };
3059 self.cfs
3060 .cfs
3061 .insert(column_family_name.as_ref().into(), ColumnFamily { inner });
3062 Ok(())
3063 }
3064
3065 pub fn drop_cf(&mut self, name: &str) -> Result<(), Error> {
3067 match self.cfs.cfs.remove(name) {
3068 Some(cf) => self.drop_column_family(cf.inner, cf),
3069 _ => Err(Error::new(format!("Invalid column family: {name}"))),
3070 }
3071 }
3072
3073 pub fn cf_handle(&self, name: &str) -> Option<&ColumnFamily> {
3075 self.cfs.cfs.get(name)
3076 }
3077
3078 pub fn cf_names(&self) -> Vec<String> {
3082 self.cfs.cfs.keys().cloned().collect()
3083 }
3084}
3085
3086impl<I: DBInner> DBCommon<MultiThreaded, I> {
3087 pub fn create_cf<N: AsRef<str>>(&self, name: N, opts: &Options) -> Result<(), Error> {
3089 let mut cfs = self.cfs.cfs.write();
3092 let inner = self.create_inner_cf_handle(name.as_ref(), opts)?;
3093 cfs.insert(
3094 name.as_ref().to_string(),
3095 Arc::new(UnboundColumnFamily { inner }),
3096 );
3097 Ok(())
3098 }
3099
3100 #[doc = include_str!("db_create_column_family_with_import.md")]
3101 pub fn create_column_family_with_import<N: AsRef<str>>(
3102 &self,
3103 options: &Options,
3104 column_family_name: N,
3105 import_options: &ImportColumnFamilyOptions,
3106 metadata: &ExportImportFilesMetaData,
3107 ) -> Result<(), Error> {
3108 let mut cfs = self.cfs.cfs.write();
3110 let name = column_family_name.as_ref();
3111 let c_name = CString::new(name).map_err(|err| {
3112 Error::new(format!(
3113 "Failed to convert name to CString while importing column family: {err}"
3114 ))
3115 })?;
3116 let inner = unsafe {
3117 ffi_try!(ffi::rocksdb_create_column_family_with_import(
3118 self.inner.inner(),
3119 options.inner,
3120 c_name.as_ptr(),
3121 import_options.inner,
3122 metadata.inner
3123 ))
3124 };
3125 cfs.insert(
3126 column_family_name.as_ref().to_string(),
3127 Arc::new(UnboundColumnFamily { inner }),
3128 );
3129 Ok(())
3130 }
3131
3132 pub fn drop_cf(&self, name: &str) -> Result<(), Error> {
3135 match self.cfs.cfs.write().remove(name) {
3136 Some(cf) => self.drop_column_family(cf.inner, cf),
3137 _ => Err(Error::new(format!("Invalid column family: {name}"))),
3138 }
3139 }
3140
3141 pub fn cf_handle(&'_ self, name: &str) -> Option<Arc<BoundColumnFamily<'_>>> {
3143 self.cfs
3144 .cfs
3145 .read()
3146 .get(name)
3147 .cloned()
3148 .map(UnboundColumnFamily::bound_column_family)
3149 }
3150
3151 pub fn cf_names(&self) -> Vec<String> {
3155 self.cfs.cfs.read().keys().cloned().collect()
3156 }
3157}
3158
3159impl<T: ThreadMode, I: DBInner> Drop for DBCommon<T, I> {
3160 fn drop(&mut self) {
3161 self.cfs.drop_all_cfs_internal();
3162 }
3163}
3164
3165impl<T: ThreadMode, I: DBInner> fmt::Debug for DBCommon<T, I> {
3166 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3167 write!(f, "RocksDB {{ path: {} }}", self.path().display())
3168 }
3169}
3170
3171#[derive(Debug, Clone)]
3173pub struct ColumnFamilyMetaData {
3174 pub size: u64,
3177 pub name: String,
3179 pub file_count: usize,
3181}
3182
3183#[derive(Debug, Clone)]
3185pub struct LiveFile {
3186 pub column_family_name: String,
3188 pub name: String,
3190 pub directory: String,
3193 pub size: usize,
3195 pub level: i32,
3197 pub start_key: Option<Vec<u8>>,
3199 pub end_key: Option<Vec<u8>>,
3201 pub smallest_seqno: u64,
3202 pub largest_seqno: u64,
3203 pub num_entries: u64,
3205 pub num_deletions: u64,
3207}
3208
3209impl LiveFile {
3210 pub(crate) fn from_rocksdb_livefiles_ptr(
3212 files: *const ffi::rocksdb_livefiles_t,
3213 ) -> Vec<LiveFile> {
3214 unsafe {
3215 let n = ffi::rocksdb_livefiles_count(files);
3216
3217 let mut livefiles = Vec::with_capacity(n as usize);
3218 let mut key_size: usize = 0;
3219
3220 for i in 0..n {
3221 let column_family_name =
3222 from_cstr(ffi::rocksdb_livefiles_column_family_name(files, i));
3223 let name = from_cstr(ffi::rocksdb_livefiles_name(files, i));
3224 let directory = from_cstr(ffi::rocksdb_livefiles_directory(files, i));
3225 let size = ffi::rocksdb_livefiles_size(files, i);
3226 let level = ffi::rocksdb_livefiles_level(files, i);
3227
3228 let smallest_key = ffi::rocksdb_livefiles_smallestkey(files, i, &mut key_size);
3230 let smallest_key = raw_data(smallest_key, key_size);
3231
3232 let largest_key = ffi::rocksdb_livefiles_largestkey(files, i, &mut key_size);
3234 let largest_key = raw_data(largest_key, key_size);
3235
3236 livefiles.push(LiveFile {
3237 column_family_name,
3238 name,
3239 directory,
3240 size,
3241 level,
3242 start_key: smallest_key,
3243 end_key: largest_key,
3244 largest_seqno: ffi::rocksdb_livefiles_largest_seqno(files, i),
3245 smallest_seqno: ffi::rocksdb_livefiles_smallest_seqno(files, i),
3246 num_entries: ffi::rocksdb_livefiles_entries(files, i),
3247 num_deletions: ffi::rocksdb_livefiles_deletions(files, i),
3248 });
3249 }
3250
3251 livefiles
3252 }
3253 }
3254}
3255
3256struct LiveFileGuard(*mut rocksdb_livefile_t);
3257
3258impl LiveFileGuard {
3259 fn into_raw(mut self) -> *mut rocksdb_livefile_t {
3260 let ptr = self.0;
3261 self.0 = ptr::null_mut();
3262 ptr
3263 }
3264}
3265
3266impl Drop for LiveFileGuard {
3267 fn drop(&mut self) {
3268 if !self.0.is_null() {
3269 unsafe {
3270 rocksdb_livefile_destroy(self.0);
3271 }
3272 }
3273 }
3274}
3275
3276struct LiveFilesGuard(*mut rocksdb_livefiles_t);
3277
3278impl LiveFilesGuard {
3279 fn into_raw(mut self) -> *mut rocksdb_livefiles_t {
3280 let ptr = self.0;
3281 self.0 = ptr::null_mut();
3282 ptr
3283 }
3284}
3285
3286impl Drop for LiveFilesGuard {
3287 fn drop(&mut self) {
3288 if !self.0.is_null() {
3289 unsafe {
3290 rocksdb_livefiles_destroy(self.0);
3291 }
3292 }
3293 }
3294}
3295
3296#[derive(Debug)]
3301pub struct ExportImportFilesMetaData {
3302 pub(crate) inner: *mut ffi::rocksdb_export_import_files_metadata_t,
3303}
3304
3305impl ExportImportFilesMetaData {
3306 pub fn get_db_comparator_name(&self) -> String {
3307 unsafe {
3308 let c_name =
3309 ffi::rocksdb_export_import_files_metadata_get_db_comparator_name(self.inner);
3310 let name = from_cstr(c_name);
3311 ffi::rocksdb_free(c_name as *mut c_void);
3312 name
3313 }
3314 }
3315
3316 pub fn set_db_comparator_name(&mut self, name: &str) {
3317 let c_name = CString::new(name.as_bytes()).unwrap();
3318 unsafe {
3319 ffi::rocksdb_export_import_files_metadata_set_db_comparator_name(
3320 self.inner,
3321 c_name.as_ptr(),
3322 );
3323 };
3324 }
3325
3326 pub fn get_files(&self) -> Vec<LiveFile> {
3327 unsafe {
3328 let livefiles_ptr = ffi::rocksdb_export_import_files_metadata_get_files(self.inner);
3329 let files = LiveFile::from_rocksdb_livefiles_ptr(livefiles_ptr);
3330 ffi::rocksdb_livefiles_destroy(livefiles_ptr);
3331 files
3332 }
3333 }
3334
3335 pub fn set_files(&mut self, files: &[LiveFile]) -> Result<(), Error> {
3336 static EMPTY: [u8; 0] = [];
3338 let empty_ptr = EMPTY.as_ptr() as *const libc::c_char;
3339
3340 unsafe {
3341 let live_files = LiveFilesGuard(ffi::rocksdb_livefiles_create());
3342
3343 for file in files {
3344 let live_file = LiveFileGuard(ffi::rocksdb_livefile_create());
3345 ffi::rocksdb_livefile_set_level(live_file.0, file.level);
3346
3347 let c_cf_name = CString::new(file.column_family_name.as_str()).map_err(|err| {
3349 Error::new(format!("Unable to convert column family to CString: {err}"))
3350 })?;
3351 ffi::rocksdb_livefile_set_column_family_name(live_file.0, c_cf_name.as_ptr());
3352
3353 let c_name = CString::new(file.name.as_str()).map_err(|err| {
3354 Error::new(format!("Unable to convert file name to CString: {err}"))
3355 })?;
3356 ffi::rocksdb_livefile_set_name(live_file.0, c_name.as_ptr());
3357
3358 let c_directory = CString::new(file.directory.as_str()).map_err(|err| {
3359 Error::new(format!("Unable to convert directory to CString: {err}"))
3360 })?;
3361 ffi::rocksdb_livefile_set_directory(live_file.0, c_directory.as_ptr());
3362
3363 ffi::rocksdb_livefile_set_size(live_file.0, file.size);
3364
3365 let (start_key_ptr, start_key_len) = match &file.start_key {
3366 None => (empty_ptr, 0),
3367 Some(key) => (key.as_ptr() as *const libc::c_char, key.len()),
3368 };
3369 ffi::rocksdb_livefile_set_smallest_key(live_file.0, start_key_ptr, start_key_len);
3370
3371 let (largest_key_ptr, largest_key_len) = match &file.end_key {
3372 None => (empty_ptr, 0),
3373 Some(key) => (key.as_ptr() as *const libc::c_char, key.len()),
3374 };
3375 ffi::rocksdb_livefile_set_largest_key(
3376 live_file.0,
3377 largest_key_ptr,
3378 largest_key_len,
3379 );
3380 ffi::rocksdb_livefile_set_smallest_seqno(live_file.0, file.smallest_seqno);
3381 ffi::rocksdb_livefile_set_largest_seqno(live_file.0, file.largest_seqno);
3382 ffi::rocksdb_livefile_set_num_entries(live_file.0, file.num_entries);
3383 ffi::rocksdb_livefile_set_num_deletions(live_file.0, file.num_deletions);
3384
3385 ffi::rocksdb_livefiles_add(live_files.0, live_file.into_raw());
3387 }
3388
3389 ffi::rocksdb_export_import_files_metadata_set_files(self.inner, live_files.into_raw());
3391 Ok(())
3392 }
3393 }
3394}
3395
3396impl Default for ExportImportFilesMetaData {
3397 fn default() -> Self {
3398 let inner = unsafe { ffi::rocksdb_export_import_files_metadata_create() };
3399 assert!(
3400 !inner.is_null(),
3401 "Could not create rocksdb_export_import_files_metadata_t"
3402 );
3403
3404 Self { inner }
3405 }
3406}
3407
3408impl Drop for ExportImportFilesMetaData {
3409 fn drop(&mut self) {
3410 unsafe {
3411 ffi::rocksdb_export_import_files_metadata_destroy(self.inner);
3412 }
3413 }
3414}
3415
3416unsafe impl Send for ExportImportFilesMetaData {}
3417unsafe impl Sync for ExportImportFilesMetaData {}
3418
3419fn convert_options(opts: &[(&str, &str)]) -> Result<Vec<(CString, CString)>, Error> {
3420 opts.iter()
3421 .map(|(name, value)| {
3422 let cname = match CString::new(name.as_bytes()) {
3423 Ok(cname) => cname,
3424 Err(e) => return Err(Error::new(format!("Invalid option name `{e}`"))),
3425 };
3426 let cvalue = match CString::new(value.as_bytes()) {
3427 Ok(cvalue) => cvalue,
3428 Err(e) => return Err(Error::new(format!("Invalid option value: `{e}`"))),
3429 };
3430 Ok((cname, cvalue))
3431 })
3432 .collect()
3433}
3434
3435pub(crate) fn convert_values(
3436 values: Vec<*mut c_char>,
3437 values_sizes: Vec<usize>,
3438 errors: Vec<*mut c_char>,
3439) -> Vec<Result<Option<Vec<u8>>, Error>> {
3440 values
3441 .into_iter()
3442 .zip(values_sizes)
3443 .zip(errors)
3444 .map(|((v, s), e)| {
3445 if e.is_null() {
3446 let value = unsafe { crate::ffi_util::raw_data(v, s) };
3447 unsafe {
3448 ffi::rocksdb_free(v as *mut c_void);
3449 }
3450 Ok(value)
3451 } else {
3452 Err(Error::new(crate::ffi_util::error_message(e)))
3453 }
3454 })
3455 .collect()
3456}