1use std::cell::RefCell;
17use std::collections::{BTreeMap, HashMap};
18use std::ffi::{CStr, CString};
19use std::fmt;
20use std::fs;
21use std::iter;
22use std::path::Path;
23use std::path::PathBuf;
24use std::ptr;
25use std::slice;
26use std::str;
27use std::sync::Arc;
28use std::time::Duration;
29
30use crate::column_family::ColumnFamilyTtl;
31use crate::ffi_util::CSlice;
32use crate::{
33 ColumnFamily, ColumnFamilyDescriptor, CompactOptions, DBIteratorWithThreadMode,
34 DBPinnableSlice, DBRawIteratorWithThreadMode, DBWALIterator, DEFAULT_COLUMN_FAMILY_NAME,
35 Direction, Error, FlushOptions, IngestExternalFileOptions, IteratorMode, Options, ReadOptions,
36 SnapshotWithThreadMode, WaitForCompactOptions, WriteBatch, WriteBatchWithIndex, WriteOptions,
37 column_family::{AsColumnFamilyRef, BoundColumnFamily, UnboundColumnFamily},
38 db_options::{ImportColumnFamilyOptions, OptionsMustOutliveDB},
39 ffi,
40 ffi_util::{
41 CStrLike, convert_rocksdb_error, from_cstr_and_free, from_cstr_without_free,
42 opt_bytes_to_ptr, raw_data, to_cpath,
43 },
44};
45use rust_librocksdb_sys::{
46 rocksdb_livefile_destroy, rocksdb_livefile_t, rocksdb_livefiles_destroy, rocksdb_livefiles_t,
47};
48
49use libc::{self, c_char, c_int, c_uchar, c_void, size_t};
50use parking_lot::RwLock;
51
52thread_local! { static DEFAULT_READ_OPTS: ReadOptions = ReadOptions::default(); }
59thread_local! { static DEFAULT_WRITE_OPTS: WriteOptions = WriteOptions::default(); }
60thread_local! { static DEFAULT_FLUSH_OPTS: FlushOptions = FlushOptions::default(); }
61thread_local! { static PREFIX_READ_OPTS: RefCell<ReadOptions> = RefCell::new({ let mut o = ReadOptions::default(); o.set_prefix_same_as_start(true); o }); }
63
64pub struct Range<'a> {
68 start_key: &'a [u8],
69 end_key: &'a [u8],
70}
71
72impl<'a> Range<'a> {
73 pub fn new(start_key: &'a [u8], end_key: &'a [u8]) -> Range<'a> {
74 Range { start_key, end_key }
75 }
76}
77
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 && let Some(k) = self.raw.key()
92 {
93 return Ok(k.starts_with(prefix));
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 &raw mut length,
987 ));
988
989 let vec = slice::from_raw_parts(ptr, length)
990 .iter()
991 .map(|ptr| from_cstr_without_free(*ptr))
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(convert_rocksdb_error(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 &raw mut val, &raw mut val_len, ptr::null(), 0, &raw 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
1575 let mut err: *mut ::libc::c_char = ::std::ptr::null_mut();
1578 let cf_handle = unsafe {
1579 ffi::rocksdb_create_column_family(
1580 self.inner.inner(),
1581 opts.inner,
1582 cf_name.as_ptr(),
1583 &raw mut err,
1584 )
1585 };
1586 if !err.is_null() {
1587 if !cf_handle.is_null() {
1588 unsafe { ffi::rocksdb_column_family_handle_destroy(cf_handle) };
1589 }
1590 return Err(convert_rocksdb_error(err));
1591 }
1592 Ok(cf_handle)
1593 }
1594
1595 pub fn iterator<'a: 'b, 'b>(
1596 &'a self,
1597 mode: IteratorMode,
1598 ) -> DBIteratorWithThreadMode<'b, Self> {
1599 let readopts = ReadOptions::default();
1600 self.iterator_opt(mode, readopts)
1601 }
1602
1603 pub fn iterator_opt<'a: 'b, 'b>(
1604 &'a self,
1605 mode: IteratorMode,
1606 readopts: ReadOptions,
1607 ) -> DBIteratorWithThreadMode<'b, Self> {
1608 DBIteratorWithThreadMode::new(self, readopts, mode)
1609 }
1610
1611 pub fn iterator_cf_opt<'a: 'b, 'b>(
1614 &'a self,
1615 cf_handle: &impl AsColumnFamilyRef,
1616 readopts: ReadOptions,
1617 mode: IteratorMode,
1618 ) -> DBIteratorWithThreadMode<'b, Self> {
1619 DBIteratorWithThreadMode::new_cf(self, cf_handle.inner(), readopts, mode)
1620 }
1621
1622 pub fn full_iterator<'a: 'b, 'b>(
1626 &'a self,
1627 mode: IteratorMode,
1628 ) -> DBIteratorWithThreadMode<'b, Self> {
1629 let mut opts = ReadOptions::default();
1630 opts.set_total_order_seek(true);
1631 DBIteratorWithThreadMode::new(self, opts, mode)
1632 }
1633
1634 pub fn prefix_iterator<'a: 'b, 'b, P: AsRef<[u8]>>(
1635 &'a self,
1636 prefix: P,
1637 ) -> DBIteratorWithThreadMode<'b, Self> {
1638 let mut opts = ReadOptions::default();
1639 opts.set_prefix_same_as_start(true);
1640 DBIteratorWithThreadMode::new(
1641 self,
1642 opts,
1643 IteratorMode::From(prefix.as_ref(), Direction::Forward),
1644 )
1645 }
1646
1647 pub fn iterator_cf<'a: 'b, 'b>(
1648 &'a self,
1649 cf_handle: &impl AsColumnFamilyRef,
1650 mode: IteratorMode,
1651 ) -> DBIteratorWithThreadMode<'b, Self> {
1652 let opts = ReadOptions::default();
1653 DBIteratorWithThreadMode::new_cf(self, cf_handle.inner(), opts, mode)
1654 }
1655
1656 pub fn full_iterator_cf<'a: 'b, 'b>(
1657 &'a self,
1658 cf_handle: &impl AsColumnFamilyRef,
1659 mode: IteratorMode,
1660 ) -> DBIteratorWithThreadMode<'b, Self> {
1661 let mut opts = ReadOptions::default();
1662 opts.set_total_order_seek(true);
1663 DBIteratorWithThreadMode::new_cf(self, cf_handle.inner(), opts, mode)
1664 }
1665
1666 pub fn prefix_iterator_cf<'a, P: AsRef<[u8]>>(
1667 &'a self,
1668 cf_handle: &impl AsColumnFamilyRef,
1669 prefix: P,
1670 ) -> DBIteratorWithThreadMode<'a, Self> {
1671 let mut opts = ReadOptions::default();
1672 opts.set_prefix_same_as_start(true);
1673 DBIteratorWithThreadMode::<'a, Self>::new_cf(
1674 self,
1675 cf_handle.inner(),
1676 opts,
1677 IteratorMode::From(prefix.as_ref(), Direction::Forward),
1678 )
1679 }
1680
1681 pub fn prefix_exists<P: AsRef<[u8]>>(&self, prefix: P) -> Result<bool, Error> {
1688 let p = prefix.as_ref();
1689 PREFIX_READ_OPTS.with(|rc| {
1690 let mut opts = rc.borrow_mut();
1691 opts.set_iterate_range(crate::PrefixRange(p));
1692 self.prefix_exists_opt(p, &opts)
1693 })
1694 }
1695
1696 pub fn prefix_exists_opt<P: AsRef<[u8]>>(
1699 &self,
1700 prefix: P,
1701 readopts: &ReadOptions,
1702 ) -> Result<bool, Error> {
1703 let prefix = prefix.as_ref();
1704 let iter = unsafe { self.create_iterator(readopts) };
1705 let res = unsafe {
1706 ffi::rocksdb_iter_seek(
1707 iter,
1708 prefix.as_ptr() as *const c_char,
1709 prefix.len() as size_t,
1710 );
1711 if ffi::rocksdb_iter_valid(iter) != 0 {
1712 let mut key_len: size_t = 0;
1713 let key_ptr = ffi::rocksdb_iter_key(iter, &raw mut key_len);
1714 let key = slice::from_raw_parts(key_ptr as *const u8, key_len as usize);
1715 Ok(key.starts_with(prefix))
1716 } else if let Err(e) = (|| {
1717 ffi_try!(ffi::rocksdb_iter_get_error(iter));
1719 Ok::<(), Error>(())
1720 })() {
1721 Err(e)
1722 } else {
1723 Ok(false)
1724 }
1725 };
1726 unsafe { ffi::rocksdb_iter_destroy(iter) };
1727 res
1728 }
1729
1730 pub fn prefix_prober(&self) -> PrefixProber<'_, Self> {
1738 let mut opts = ReadOptions::default();
1739 opts.set_prefix_same_as_start(true);
1740 PrefixProber {
1741 raw: DBRawIteratorWithThreadMode::new(self, opts),
1742 }
1743 }
1744
1745 pub fn prefix_prober_with_opts(&self, readopts: ReadOptions) -> PrefixProber<'_, Self> {
1752 PrefixProber {
1753 raw: DBRawIteratorWithThreadMode::new(self, readopts),
1754 }
1755 }
1756
1757 pub fn prefix_prober_cf(&self, cf_handle: &impl AsColumnFamilyRef) -> PrefixProber<'_, Self> {
1760 let mut opts = ReadOptions::default();
1761 opts.set_prefix_same_as_start(true);
1762 PrefixProber {
1763 raw: DBRawIteratorWithThreadMode::new_cf(self, cf_handle.inner(), opts),
1764 }
1765 }
1766
1767 pub fn prefix_prober_cf_with_opts(
1772 &self,
1773 cf_handle: &impl AsColumnFamilyRef,
1774 readopts: ReadOptions,
1775 ) -> PrefixProber<'_, Self> {
1776 PrefixProber {
1777 raw: DBRawIteratorWithThreadMode::new_cf(self, cf_handle.inner(), readopts),
1778 }
1779 }
1780
1781 pub fn prefix_exists_cf<P: AsRef<[u8]>>(
1787 &self,
1788 cf_handle: &impl AsColumnFamilyRef,
1789 prefix: P,
1790 ) -> Result<bool, Error> {
1791 let p = prefix.as_ref();
1792 PREFIX_READ_OPTS.with(|rc| {
1793 let mut opts = rc.borrow_mut();
1794 opts.set_iterate_range(crate::PrefixRange(p));
1795 self.prefix_exists_cf_opt(cf_handle, p, &opts)
1796 })
1797 }
1798
1799 pub fn prefix_exists_cf_opt<P: AsRef<[u8]>>(
1802 &self,
1803 cf_handle: &impl AsColumnFamilyRef,
1804 prefix: P,
1805 readopts: &ReadOptions,
1806 ) -> Result<bool, Error> {
1807 let prefix = prefix.as_ref();
1808 let iter = unsafe { self.create_iterator_cf(cf_handle.inner(), readopts) };
1809 let res = unsafe {
1810 ffi::rocksdb_iter_seek(
1811 iter,
1812 prefix.as_ptr() as *const c_char,
1813 prefix.len() as size_t,
1814 );
1815 if ffi::rocksdb_iter_valid(iter) != 0 {
1816 let mut key_len: size_t = 0;
1817 let key_ptr = ffi::rocksdb_iter_key(iter, &raw mut key_len);
1818 let key = slice::from_raw_parts(key_ptr as *const u8, key_len as usize);
1819 Ok(key.starts_with(prefix))
1820 } else if let Err(e) = (|| {
1821 ffi_try!(ffi::rocksdb_iter_get_error(iter));
1822 Ok::<(), Error>(())
1823 })() {
1824 Err(e)
1825 } else {
1826 Ok(false)
1827 }
1828 };
1829 unsafe { ffi::rocksdb_iter_destroy(iter) };
1830 res
1831 }
1832
1833 pub fn raw_iterator<'a: 'b, 'b>(&'a self) -> DBRawIteratorWithThreadMode<'b, Self> {
1835 let opts = ReadOptions::default();
1836 DBRawIteratorWithThreadMode::new(self, opts)
1837 }
1838
1839 pub fn raw_iterator_cf<'a: 'b, 'b>(
1841 &'a self,
1842 cf_handle: &impl AsColumnFamilyRef,
1843 ) -> DBRawIteratorWithThreadMode<'b, Self> {
1844 let opts = ReadOptions::default();
1845 DBRawIteratorWithThreadMode::new_cf(self, cf_handle.inner(), opts)
1846 }
1847
1848 pub fn raw_iterator_opt<'a: 'b, 'b>(
1850 &'a self,
1851 readopts: ReadOptions,
1852 ) -> DBRawIteratorWithThreadMode<'b, Self> {
1853 DBRawIteratorWithThreadMode::new(self, readopts)
1854 }
1855
1856 pub fn raw_iterator_cf_opt<'a: 'b, 'b>(
1858 &'a self,
1859 cf_handle: &impl AsColumnFamilyRef,
1860 readopts: ReadOptions,
1861 ) -> DBRawIteratorWithThreadMode<'b, Self> {
1862 DBRawIteratorWithThreadMode::new_cf(self, cf_handle.inner(), readopts)
1863 }
1864
1865 pub fn snapshot(&'_ self) -> SnapshotWithThreadMode<'_, Self> {
1866 SnapshotWithThreadMode::<Self>::new(self)
1867 }
1868
1869 pub fn put_opt<K, V>(&self, key: K, value: V, writeopts: &WriteOptions) -> Result<(), Error>
1870 where
1871 K: AsRef<[u8]>,
1872 V: AsRef<[u8]>,
1873 {
1874 let key = key.as_ref();
1875 let value = value.as_ref();
1876
1877 unsafe {
1878 ffi_try!(ffi::rocksdb_put(
1879 self.inner.inner(),
1880 writeopts.inner,
1881 key.as_ptr() as *const c_char,
1882 key.len() as size_t,
1883 value.as_ptr() as *const c_char,
1884 value.len() as size_t,
1885 ));
1886 Ok(())
1887 }
1888 }
1889
1890 pub fn put_cf_opt<K, V>(
1891 &self,
1892 cf: &impl AsColumnFamilyRef,
1893 key: K,
1894 value: V,
1895 writeopts: &WriteOptions,
1896 ) -> Result<(), Error>
1897 where
1898 K: AsRef<[u8]>,
1899 V: AsRef<[u8]>,
1900 {
1901 let key = key.as_ref();
1902 let value = value.as_ref();
1903
1904 unsafe {
1905 ffi_try!(ffi::rocksdb_put_cf(
1906 self.inner.inner(),
1907 writeopts.inner,
1908 cf.inner(),
1909 key.as_ptr() as *const c_char,
1910 key.len() as size_t,
1911 value.as_ptr() as *const c_char,
1912 value.len() as size_t,
1913 ));
1914 Ok(())
1915 }
1916 }
1917
1918 pub fn put_with_ts_opt<K, V, S>(
1925 &self,
1926 key: K,
1927 ts: S,
1928 value: V,
1929 writeopts: &WriteOptions,
1930 ) -> Result<(), Error>
1931 where
1932 K: AsRef<[u8]>,
1933 V: AsRef<[u8]>,
1934 S: AsRef<[u8]>,
1935 {
1936 let key = key.as_ref();
1937 let value = value.as_ref();
1938 let ts = ts.as_ref();
1939 unsafe {
1940 ffi_try!(ffi::rocksdb_put_with_ts(
1941 self.inner.inner(),
1942 writeopts.inner,
1943 key.as_ptr() as *const c_char,
1944 key.len() as size_t,
1945 ts.as_ptr() as *const c_char,
1946 ts.len() as size_t,
1947 value.as_ptr() as *const c_char,
1948 value.len() as size_t,
1949 ));
1950 Ok(())
1951 }
1952 }
1953
1954 pub fn put_cf_with_ts_opt<K, V, S>(
1961 &self,
1962 cf: &impl AsColumnFamilyRef,
1963 key: K,
1964 ts: S,
1965 value: V,
1966 writeopts: &WriteOptions,
1967 ) -> Result<(), Error>
1968 where
1969 K: AsRef<[u8]>,
1970 V: AsRef<[u8]>,
1971 S: AsRef<[u8]>,
1972 {
1973 let key = key.as_ref();
1974 let value = value.as_ref();
1975 let ts = ts.as_ref();
1976 unsafe {
1977 ffi_try!(ffi::rocksdb_put_cf_with_ts(
1978 self.inner.inner(),
1979 writeopts.inner,
1980 cf.inner(),
1981 key.as_ptr() as *const c_char,
1982 key.len() as size_t,
1983 ts.as_ptr() as *const c_char,
1984 ts.len() as size_t,
1985 value.as_ptr() as *const c_char,
1986 value.len() as size_t,
1987 ));
1988 Ok(())
1989 }
1990 }
1991
1992 pub fn merge_opt<K, V>(&self, key: K, value: V, writeopts: &WriteOptions) -> Result<(), Error>
1993 where
1994 K: AsRef<[u8]>,
1995 V: AsRef<[u8]>,
1996 {
1997 let key = key.as_ref();
1998 let value = value.as_ref();
1999
2000 unsafe {
2001 ffi_try!(ffi::rocksdb_merge(
2002 self.inner.inner(),
2003 writeopts.inner,
2004 key.as_ptr() as *const c_char,
2005 key.len() as size_t,
2006 value.as_ptr() as *const c_char,
2007 value.len() as size_t,
2008 ));
2009 Ok(())
2010 }
2011 }
2012
2013 pub fn merge_cf_opt<K, V>(
2014 &self,
2015 cf: &impl AsColumnFamilyRef,
2016 key: K,
2017 value: V,
2018 writeopts: &WriteOptions,
2019 ) -> Result<(), Error>
2020 where
2021 K: AsRef<[u8]>,
2022 V: AsRef<[u8]>,
2023 {
2024 let key = key.as_ref();
2025 let value = value.as_ref();
2026
2027 unsafe {
2028 ffi_try!(ffi::rocksdb_merge_cf(
2029 self.inner.inner(),
2030 writeopts.inner,
2031 cf.inner(),
2032 key.as_ptr() as *const c_char,
2033 key.len() as size_t,
2034 value.as_ptr() as *const c_char,
2035 value.len() as size_t,
2036 ));
2037 Ok(())
2038 }
2039 }
2040
2041 pub fn delete_opt<K: AsRef<[u8]>>(
2042 &self,
2043 key: K,
2044 writeopts: &WriteOptions,
2045 ) -> Result<(), Error> {
2046 let key = key.as_ref();
2047
2048 unsafe {
2049 ffi_try!(ffi::rocksdb_delete(
2050 self.inner.inner(),
2051 writeopts.inner,
2052 key.as_ptr() as *const c_char,
2053 key.len() as size_t,
2054 ));
2055 Ok(())
2056 }
2057 }
2058
2059 pub fn delete_cf_opt<K: AsRef<[u8]>>(
2060 &self,
2061 cf: &impl AsColumnFamilyRef,
2062 key: K,
2063 writeopts: &WriteOptions,
2064 ) -> Result<(), Error> {
2065 let key = key.as_ref();
2066
2067 unsafe {
2068 ffi_try!(ffi::rocksdb_delete_cf(
2069 self.inner.inner(),
2070 writeopts.inner,
2071 cf.inner(),
2072 key.as_ptr() as *const c_char,
2073 key.len() as size_t,
2074 ));
2075 Ok(())
2076 }
2077 }
2078
2079 pub fn delete_with_ts_opt<K, S>(
2083 &self,
2084 key: K,
2085 ts: S,
2086 writeopts: &WriteOptions,
2087 ) -> Result<(), Error>
2088 where
2089 K: AsRef<[u8]>,
2090 S: AsRef<[u8]>,
2091 {
2092 let key = key.as_ref();
2093 let ts = ts.as_ref();
2094 unsafe {
2095 ffi_try!(ffi::rocksdb_delete_with_ts(
2096 self.inner.inner(),
2097 writeopts.inner,
2098 key.as_ptr() as *const c_char,
2099 key.len() as size_t,
2100 ts.as_ptr() as *const c_char,
2101 ts.len() as size_t,
2102 ));
2103 Ok(())
2104 }
2105 }
2106
2107 pub fn delete_cf_with_ts_opt<K, S>(
2111 &self,
2112 cf: &impl AsColumnFamilyRef,
2113 key: K,
2114 ts: S,
2115 writeopts: &WriteOptions,
2116 ) -> Result<(), Error>
2117 where
2118 K: AsRef<[u8]>,
2119 S: AsRef<[u8]>,
2120 {
2121 let key = key.as_ref();
2122 let ts = ts.as_ref();
2123 unsafe {
2124 ffi_try!(ffi::rocksdb_delete_cf_with_ts(
2125 self.inner.inner(),
2126 writeopts.inner,
2127 cf.inner(),
2128 key.as_ptr() as *const c_char,
2129 key.len() as size_t,
2130 ts.as_ptr() as *const c_char,
2131 ts.len() as size_t,
2132 ));
2133 Ok(())
2134 }
2135 }
2136
2137 pub fn put<K, V>(&self, key: K, value: V) -> Result<(), Error>
2138 where
2139 K: AsRef<[u8]>,
2140 V: AsRef<[u8]>,
2141 {
2142 DEFAULT_WRITE_OPTS.with(|opts| self.put_opt(key, value, opts))
2143 }
2144
2145 pub fn put_cf<K, V>(&self, cf: &impl AsColumnFamilyRef, key: K, value: V) -> Result<(), Error>
2146 where
2147 K: AsRef<[u8]>,
2148 V: AsRef<[u8]>,
2149 {
2150 DEFAULT_WRITE_OPTS.with(|opts| self.put_cf_opt(cf, key, value, opts))
2151 }
2152
2153 pub fn put_with_ts<K, V, S>(&self, key: K, ts: S, value: V) -> Result<(), Error>
2160 where
2161 K: AsRef<[u8]>,
2162 V: AsRef<[u8]>,
2163 S: AsRef<[u8]>,
2164 {
2165 DEFAULT_WRITE_OPTS
2166 .with(|opts| self.put_with_ts_opt(key.as_ref(), ts.as_ref(), value.as_ref(), opts))
2167 }
2168
2169 pub fn put_cf_with_ts<K, V, S>(
2176 &self,
2177 cf: &impl AsColumnFamilyRef,
2178 key: K,
2179 ts: S,
2180 value: V,
2181 ) -> Result<(), Error>
2182 where
2183 K: AsRef<[u8]>,
2184 V: AsRef<[u8]>,
2185 S: AsRef<[u8]>,
2186 {
2187 DEFAULT_WRITE_OPTS.with(|opts| {
2188 self.put_cf_with_ts_opt(cf, key.as_ref(), ts.as_ref(), value.as_ref(), opts)
2189 })
2190 }
2191
2192 pub fn merge<K, V>(&self, key: K, value: V) -> Result<(), Error>
2193 where
2194 K: AsRef<[u8]>,
2195 V: AsRef<[u8]>,
2196 {
2197 DEFAULT_WRITE_OPTS.with(|opts| self.merge_opt(key, value, opts))
2198 }
2199
2200 pub fn merge_cf<K, V>(&self, cf: &impl AsColumnFamilyRef, key: K, value: V) -> Result<(), Error>
2201 where
2202 K: AsRef<[u8]>,
2203 V: AsRef<[u8]>,
2204 {
2205 DEFAULT_WRITE_OPTS.with(|opts| self.merge_cf_opt(cf, key, value, opts))
2206 }
2207
2208 pub fn delete<K: AsRef<[u8]>>(&self, key: K) -> Result<(), Error> {
2209 DEFAULT_WRITE_OPTS.with(|opts| self.delete_opt(key, opts))
2210 }
2211
2212 pub fn delete_cf<K: AsRef<[u8]>>(
2213 &self,
2214 cf: &impl AsColumnFamilyRef,
2215 key: K,
2216 ) -> Result<(), Error> {
2217 DEFAULT_WRITE_OPTS.with(|opts| self.delete_cf_opt(cf, key, opts))
2218 }
2219
2220 pub fn delete_with_ts<K: AsRef<[u8]>, S: AsRef<[u8]>>(
2224 &self,
2225 key: K,
2226 ts: S,
2227 ) -> Result<(), Error> {
2228 DEFAULT_WRITE_OPTS.with(|opts| self.delete_with_ts_opt(key, ts, opts))
2229 }
2230
2231 pub fn delete_cf_with_ts<K: AsRef<[u8]>, S: AsRef<[u8]>>(
2235 &self,
2236 cf: &impl AsColumnFamilyRef,
2237 key: K,
2238 ts: S,
2239 ) -> Result<(), Error> {
2240 DEFAULT_WRITE_OPTS.with(|opts| self.delete_cf_with_ts_opt(cf, key, ts, opts))
2241 }
2242
2243 pub fn single_delete_opt<K: AsRef<[u8]>>(
2263 &self,
2264 key: K,
2265 writeopts: &WriteOptions,
2266 ) -> Result<(), Error> {
2267 let key = key.as_ref();
2268
2269 unsafe {
2270 ffi_try!(ffi::rocksdb_singledelete(
2271 self.inner.inner(),
2272 writeopts.inner,
2273 key.as_ptr() as *const c_char,
2274 key.len() as size_t,
2275 ));
2276 Ok(())
2277 }
2278 }
2279
2280 pub fn single_delete_cf_opt<K: AsRef<[u8]>>(
2284 &self,
2285 cf: &impl AsColumnFamilyRef,
2286 key: K,
2287 writeopts: &WriteOptions,
2288 ) -> Result<(), Error> {
2289 let key = key.as_ref();
2290
2291 unsafe {
2292 ffi_try!(ffi::rocksdb_singledelete_cf(
2293 self.inner.inner(),
2294 writeopts.inner,
2295 cf.inner(),
2296 key.as_ptr() as *const c_char,
2297 key.len() as size_t,
2298 ));
2299 Ok(())
2300 }
2301 }
2302
2303 pub fn single_delete_with_ts_opt<K, S>(
2310 &self,
2311 key: K,
2312 ts: S,
2313 writeopts: &WriteOptions,
2314 ) -> Result<(), Error>
2315 where
2316 K: AsRef<[u8]>,
2317 S: AsRef<[u8]>,
2318 {
2319 let key = key.as_ref();
2320 let ts = ts.as_ref();
2321 unsafe {
2322 ffi_try!(ffi::rocksdb_singledelete_with_ts(
2323 self.inner.inner(),
2324 writeopts.inner,
2325 key.as_ptr() as *const c_char,
2326 key.len() as size_t,
2327 ts.as_ptr() as *const c_char,
2328 ts.len() as size_t,
2329 ));
2330 Ok(())
2331 }
2332 }
2333
2334 pub fn single_delete_cf_with_ts_opt<K, S>(
2341 &self,
2342 cf: &impl AsColumnFamilyRef,
2343 key: K,
2344 ts: S,
2345 writeopts: &WriteOptions,
2346 ) -> Result<(), Error>
2347 where
2348 K: AsRef<[u8]>,
2349 S: AsRef<[u8]>,
2350 {
2351 let key = key.as_ref();
2352 let ts = ts.as_ref();
2353 unsafe {
2354 ffi_try!(ffi::rocksdb_singledelete_cf_with_ts(
2355 self.inner.inner(),
2356 writeopts.inner,
2357 cf.inner(),
2358 key.as_ptr() as *const c_char,
2359 key.len() as size_t,
2360 ts.as_ptr() as *const c_char,
2361 ts.len() as size_t,
2362 ));
2363 Ok(())
2364 }
2365 }
2366
2367 pub fn single_delete<K: AsRef<[u8]>>(&self, key: K) -> Result<(), Error> {
2371 DEFAULT_WRITE_OPTS.with(|opts| self.single_delete_opt(key, opts))
2372 }
2373
2374 pub fn single_delete_cf<K: AsRef<[u8]>>(
2378 &self,
2379 cf: &impl AsColumnFamilyRef,
2380 key: K,
2381 ) -> Result<(), Error> {
2382 DEFAULT_WRITE_OPTS.with(|opts| self.single_delete_cf_opt(cf, key, opts))
2383 }
2384
2385 pub fn single_delete_with_ts<K: AsRef<[u8]>, S: AsRef<[u8]>>(
2392 &self,
2393 key: K,
2394 ts: S,
2395 ) -> Result<(), Error> {
2396 DEFAULT_WRITE_OPTS.with(|opts| self.single_delete_with_ts_opt(key, ts, opts))
2397 }
2398
2399 pub fn single_delete_cf_with_ts<K: AsRef<[u8]>, S: AsRef<[u8]>>(
2406 &self,
2407 cf: &impl AsColumnFamilyRef,
2408 key: K,
2409 ts: S,
2410 ) -> Result<(), Error> {
2411 DEFAULT_WRITE_OPTS.with(|opts| self.single_delete_cf_with_ts_opt(cf, key, ts, opts))
2412 }
2413
2414 pub fn compact_range<S: AsRef<[u8]>, E: AsRef<[u8]>>(&self, start: Option<S>, end: Option<E>) {
2416 unsafe {
2417 let start = start.as_ref().map(AsRef::as_ref);
2418 let end = end.as_ref().map(AsRef::as_ref);
2419
2420 ffi::rocksdb_compact_range(
2421 self.inner.inner(),
2422 opt_bytes_to_ptr(start),
2423 start.map_or(0, <[u8]>::len) as size_t,
2424 opt_bytes_to_ptr(end),
2425 end.map_or(0, <[u8]>::len) as size_t,
2426 );
2427 }
2428 }
2429
2430 pub fn compact_range_opt<S: AsRef<[u8]>, E: AsRef<[u8]>>(
2432 &self,
2433 start: Option<S>,
2434 end: Option<E>,
2435 opts: &CompactOptions,
2436 ) {
2437 unsafe {
2438 let start = start.as_ref().map(AsRef::as_ref);
2439 let end = end.as_ref().map(AsRef::as_ref);
2440
2441 ffi::rocksdb_compact_range_opt(
2442 self.inner.inner(),
2443 opts.inner,
2444 opt_bytes_to_ptr(start),
2445 start.map_or(0, <[u8]>::len) as size_t,
2446 opt_bytes_to_ptr(end),
2447 end.map_or(0, <[u8]>::len) as size_t,
2448 );
2449 }
2450 }
2451
2452 pub fn compact_range_cf<S: AsRef<[u8]>, E: AsRef<[u8]>>(
2455 &self,
2456 cf: &impl AsColumnFamilyRef,
2457 start: Option<S>,
2458 end: Option<E>,
2459 ) {
2460 unsafe {
2461 let start = start.as_ref().map(AsRef::as_ref);
2462 let end = end.as_ref().map(AsRef::as_ref);
2463
2464 ffi::rocksdb_compact_range_cf(
2465 self.inner.inner(),
2466 cf.inner(),
2467 opt_bytes_to_ptr(start),
2468 start.map_or(0, <[u8]>::len) as size_t,
2469 opt_bytes_to_ptr(end),
2470 end.map_or(0, <[u8]>::len) as size_t,
2471 );
2472 }
2473 }
2474
2475 pub fn compact_range_cf_opt<S: AsRef<[u8]>, E: AsRef<[u8]>>(
2477 &self,
2478 cf: &impl AsColumnFamilyRef,
2479 start: Option<S>,
2480 end: Option<E>,
2481 opts: &CompactOptions,
2482 ) {
2483 unsafe {
2484 let start = start.as_ref().map(AsRef::as_ref);
2485 let end = end.as_ref().map(AsRef::as_ref);
2486
2487 ffi::rocksdb_compact_range_cf_opt(
2488 self.inner.inner(),
2489 cf.inner(),
2490 opts.inner,
2491 opt_bytes_to_ptr(start),
2492 start.map_or(0, <[u8]>::len) as size_t,
2493 opt_bytes_to_ptr(end),
2494 end.map_or(0, <[u8]>::len) as size_t,
2495 );
2496 }
2497 }
2498
2499 pub fn wait_for_compact(&self, opts: &WaitForCompactOptions) -> Result<(), Error> {
2508 unsafe {
2509 ffi_try!(ffi::rocksdb_wait_for_compact(
2510 self.inner.inner(),
2511 opts.inner
2512 ));
2513 }
2514 Ok(())
2515 }
2516
2517 pub fn set_options(&self, opts: &[(&str, &str)]) -> Result<(), Error> {
2518 let copts = convert_options(opts)?;
2519 let cnames: Vec<*const c_char> = copts.iter().map(|opt| opt.0.as_ptr()).collect();
2520 let cvalues: Vec<*const c_char> = copts.iter().map(|opt| opt.1.as_ptr()).collect();
2521 let count = opts.len() as i32;
2522 unsafe {
2523 ffi_try!(ffi::rocksdb_set_options(
2524 self.inner.inner(),
2525 count,
2526 cnames.as_ptr(),
2527 cvalues.as_ptr(),
2528 ));
2529 }
2530 Ok(())
2531 }
2532
2533 pub fn set_options_cf(
2534 &self,
2535 cf: &impl AsColumnFamilyRef,
2536 opts: &[(&str, &str)],
2537 ) -> Result<(), Error> {
2538 let copts = convert_options(opts)?;
2539 let cnames: Vec<*const c_char> = copts.iter().map(|opt| opt.0.as_ptr()).collect();
2540 let cvalues: Vec<*const c_char> = copts.iter().map(|opt| opt.1.as_ptr()).collect();
2541 let count = opts.len() as i32;
2542 unsafe {
2543 ffi_try!(ffi::rocksdb_set_options_cf(
2544 self.inner.inner(),
2545 cf.inner(),
2546 count,
2547 cnames.as_ptr(),
2548 cvalues.as_ptr(),
2549 ));
2550 }
2551 Ok(())
2552 }
2553
2554 fn property_value_impl<R>(
2563 name: impl CStrLike,
2564 get_property: impl FnOnce(*const c_char) -> *mut c_char,
2565 parse: impl FnOnce(&str) -> Result<R, Error>,
2566 ) -> Result<Option<R>, Error> {
2567 let value = match name.bake() {
2568 Ok(prop_name) => get_property(prop_name.as_ptr()),
2569 Err(e) => {
2570 return Err(Error::new(format!(
2571 "Failed to convert property name to CString: {e}"
2572 )));
2573 }
2574 };
2575 if value.is_null() {
2576 return Ok(None);
2577 }
2578 let result = match unsafe { CStr::from_ptr(value) }.to_str() {
2579 Ok(s) => parse(s).map(|value| Some(value)),
2580 Err(e) => Err(Error::new(format!(
2581 "Failed to convert property value to string: {e}"
2582 ))),
2583 };
2584 unsafe {
2585 ffi::rocksdb_free(value as *mut c_void);
2586 }
2587 result
2588 }
2589
2590 pub fn property_value(&self, name: impl CStrLike) -> Result<Option<String>, Error> {
2595 Self::property_value_impl(
2596 name,
2597 |prop_name| unsafe { ffi::rocksdb_property_value(self.inner.inner(), prop_name) },
2598 |str_value| Ok(str_value.to_owned()),
2599 )
2600 }
2601
2602 pub fn property_value_cf(
2607 &self,
2608 cf: &impl AsColumnFamilyRef,
2609 name: impl CStrLike,
2610 ) -> Result<Option<String>, Error> {
2611 Self::property_value_impl(
2612 name,
2613 |prop_name| unsafe {
2614 ffi::rocksdb_property_value_cf(self.inner.inner(), cf.inner(), prop_name)
2615 },
2616 |str_value| Ok(str_value.to_owned()),
2617 )
2618 }
2619
2620 fn parse_property_int_value(value: &str) -> Result<u64, Error> {
2621 value.parse::<u64>().map_err(|err| {
2622 Error::new(format!(
2623 "Failed to convert property value {value} to int: {err}"
2624 ))
2625 })
2626 }
2627
2628 pub fn property_int_value(&self, name: impl CStrLike) -> Result<Option<u64>, Error> {
2633 Self::property_value_impl(
2634 name,
2635 |prop_name| unsafe { ffi::rocksdb_property_value(self.inner.inner(), prop_name) },
2636 Self::parse_property_int_value,
2637 )
2638 }
2639
2640 pub fn property_int_value_cf(
2645 &self,
2646 cf: &impl AsColumnFamilyRef,
2647 name: impl CStrLike,
2648 ) -> Result<Option<u64>, Error> {
2649 Self::property_value_impl(
2650 name,
2651 |prop_name| unsafe {
2652 ffi::rocksdb_property_value_cf(self.inner.inner(), cf.inner(), prop_name)
2653 },
2654 Self::parse_property_int_value,
2655 )
2656 }
2657
2658 pub fn latest_sequence_number(&self) -> u64 {
2660 unsafe { ffi::rocksdb_get_latest_sequence_number(self.inner.inner()) }
2661 }
2662
2663 pub fn get_approximate_sizes(&self, ranges: &[Range]) -> Vec<u64> {
2671 self.get_approximate_sizes_cfopt(None::<&ColumnFamily>, ranges)
2672 }
2673
2674 pub fn get_approximate_sizes_cf(
2675 &self,
2676 cf: &impl AsColumnFamilyRef,
2677 ranges: &[Range],
2678 ) -> Vec<u64> {
2679 self.get_approximate_sizes_cfopt(Some(cf), ranges)
2680 }
2681
2682 fn get_approximate_sizes_cfopt(
2683 &self,
2684 cf: Option<&impl AsColumnFamilyRef>,
2685 ranges: &[Range],
2686 ) -> Vec<u64> {
2687 let start_keys: Vec<*const c_char> = ranges
2688 .iter()
2689 .map(|x| x.start_key.as_ptr() as *const c_char)
2690 .collect();
2691 let start_key_lens: Vec<_> = ranges.iter().map(|x| x.start_key.len()).collect();
2692 let end_keys: Vec<*const c_char> = ranges
2693 .iter()
2694 .map(|x| x.end_key.as_ptr() as *const c_char)
2695 .collect();
2696 let end_key_lens: Vec<_> = ranges.iter().map(|x| x.end_key.len()).collect();
2697 let mut sizes: Vec<u64> = vec![0; ranges.len()];
2698 let (n, start_key_ptr, start_key_len_ptr, end_key_ptr, end_key_len_ptr, size_ptr) = (
2699 ranges.len() as i32,
2700 start_keys.as_ptr(),
2701 start_key_lens.as_ptr(),
2702 end_keys.as_ptr(),
2703 end_key_lens.as_ptr(),
2704 sizes.as_mut_ptr(),
2705 );
2706 let mut err: *mut c_char = ptr::null_mut();
2707 match cf {
2708 None => unsafe {
2709 ffi::rocksdb_approximate_sizes(
2710 self.inner.inner(),
2711 n,
2712 start_key_ptr,
2713 start_key_len_ptr,
2714 end_key_ptr,
2715 end_key_len_ptr,
2716 size_ptr,
2717 &raw mut err,
2718 );
2719 },
2720 Some(cf) => unsafe {
2721 ffi::rocksdb_approximate_sizes_cf(
2722 self.inner.inner(),
2723 cf.inner(),
2724 n,
2725 start_key_ptr,
2726 start_key_len_ptr,
2727 end_key_ptr,
2728 end_key_len_ptr,
2729 size_ptr,
2730 &raw mut err,
2731 );
2732 },
2733 }
2734 sizes
2735 }
2736
2737 pub fn get_updates_since(&self, seq_number: u64) -> Result<DBWALIterator, Error> {
2748 unsafe {
2749 let opts: *const ffi::rocksdb_wal_readoptions_t = ptr::null();
2753 let iter = ffi_try!(ffi::rocksdb_get_updates_since(
2754 self.inner.inner(),
2755 seq_number,
2756 opts
2757 ));
2758 Ok(DBWALIterator {
2759 inner: iter,
2760 start_seq_number: seq_number,
2761 })
2762 }
2763 }
2764
2765 pub fn try_catch_up_with_primary(&self) -> Result<(), Error> {
2768 unsafe {
2769 ffi_try!(ffi::rocksdb_try_catch_up_with_primary(self.inner.inner()));
2770 }
2771 Ok(())
2772 }
2773
2774 pub fn ingest_external_file<P: AsRef<Path>>(&self, paths: Vec<P>) -> Result<(), Error> {
2776 let opts = IngestExternalFileOptions::default();
2777 self.ingest_external_file_opts(&opts, paths)
2778 }
2779
2780 pub fn ingest_external_file_opts<P: AsRef<Path>>(
2782 &self,
2783 opts: &IngestExternalFileOptions,
2784 paths: Vec<P>,
2785 ) -> Result<(), Error> {
2786 let paths_v: Vec<CString> = paths.iter().map(to_cpath).collect::<Result<Vec<_>, _>>()?;
2787 let cpaths: Vec<_> = paths_v.iter().map(|path| path.as_ptr()).collect();
2788
2789 self.ingest_external_file_raw(opts, &paths_v, &cpaths)
2790 }
2791
2792 pub fn ingest_external_file_cf<P: AsRef<Path>>(
2795 &self,
2796 cf: &impl AsColumnFamilyRef,
2797 paths: Vec<P>,
2798 ) -> Result<(), Error> {
2799 let opts = IngestExternalFileOptions::default();
2800 self.ingest_external_file_cf_opts(cf, &opts, paths)
2801 }
2802
2803 pub fn ingest_external_file_cf_opts<P: AsRef<Path>>(
2805 &self,
2806 cf: &impl AsColumnFamilyRef,
2807 opts: &IngestExternalFileOptions,
2808 paths: Vec<P>,
2809 ) -> Result<(), Error> {
2810 let paths_v: Vec<CString> = paths.iter().map(to_cpath).collect::<Result<Vec<_>, _>>()?;
2811 let cpaths: Vec<_> = paths_v.iter().map(|path| path.as_ptr()).collect();
2812
2813 self.ingest_external_file_raw_cf(cf, opts, &paths_v, &cpaths)
2814 }
2815
2816 fn ingest_external_file_raw(
2817 &self,
2818 opts: &IngestExternalFileOptions,
2819 paths_v: &[CString],
2820 cpaths: &[*const c_char],
2821 ) -> Result<(), Error> {
2822 unsafe {
2823 ffi_try!(ffi::rocksdb_ingest_external_file(
2824 self.inner.inner(),
2825 cpaths.as_ptr(),
2826 paths_v.len(),
2827 opts.inner.cast_const()
2828 ));
2829 Ok(())
2830 }
2831 }
2832
2833 fn ingest_external_file_raw_cf(
2834 &self,
2835 cf: &impl AsColumnFamilyRef,
2836 opts: &IngestExternalFileOptions,
2837 paths_v: &[CString],
2838 cpaths: &[*const c_char],
2839 ) -> Result<(), Error> {
2840 unsafe {
2841 ffi_try!(ffi::rocksdb_ingest_external_file_cf(
2842 self.inner.inner(),
2843 cf.inner(),
2844 cpaths.as_ptr(),
2845 paths_v.len(),
2846 opts.inner.cast_const()
2847 ));
2848 Ok(())
2849 }
2850 }
2851
2852 pub fn get_column_family_metadata(&self) -> ColumnFamilyMetaData {
2854 unsafe {
2855 let ptr = ffi::rocksdb_get_column_family_metadata(self.inner.inner());
2856
2857 let metadata = ColumnFamilyMetaData {
2858 size: ffi::rocksdb_column_family_metadata_get_size(ptr),
2859 name: from_cstr_and_free(ffi::rocksdb_column_family_metadata_get_name(ptr)),
2860 file_count: ffi::rocksdb_column_family_metadata_get_file_count(ptr),
2861 };
2862
2863 ffi::rocksdb_column_family_metadata_destroy(ptr);
2865
2866 metadata
2868 }
2869 }
2870
2871 pub fn get_column_family_metadata_cf(
2873 &self,
2874 cf: &impl AsColumnFamilyRef,
2875 ) -> ColumnFamilyMetaData {
2876 unsafe {
2877 let ptr = ffi::rocksdb_get_column_family_metadata_cf(self.inner.inner(), cf.inner());
2878
2879 let metadata = ColumnFamilyMetaData {
2880 size: ffi::rocksdb_column_family_metadata_get_size(ptr),
2881 name: from_cstr_and_free(ffi::rocksdb_column_family_metadata_get_name(ptr)),
2882 file_count: ffi::rocksdb_column_family_metadata_get_file_count(ptr),
2883 };
2884
2885 ffi::rocksdb_column_family_metadata_destroy(ptr);
2887
2888 metadata
2890 }
2891 }
2892
2893 pub fn live_files(&self) -> Result<Vec<LiveFile>, Error> {
2896 unsafe {
2897 let livefiles_ptr = ffi::rocksdb_livefiles(self.inner.inner());
2898 if livefiles_ptr.is_null() {
2899 Err(Error::new("Could not get live files".to_owned()))
2900 } else {
2901 let files = LiveFile::from_rocksdb_livefiles_ptr(livefiles_ptr);
2902
2903 ffi::rocksdb_livefiles_destroy(livefiles_ptr);
2905
2906 Ok(files)
2908 }
2909 }
2910 }
2911
2912 pub fn delete_file_in_range<K: AsRef<[u8]>>(&self, from: K, to: K) -> Result<(), Error> {
2921 let from = from.as_ref();
2922 let to = to.as_ref();
2923 unsafe {
2924 ffi_try!(ffi::rocksdb_delete_file_in_range(
2925 self.inner.inner(),
2926 from.as_ptr() as *const c_char,
2927 from.len() as size_t,
2928 to.as_ptr() as *const c_char,
2929 to.len() as size_t,
2930 ));
2931 Ok(())
2932 }
2933 }
2934
2935 pub fn delete_file_in_range_cf<K: AsRef<[u8]>>(
2937 &self,
2938 cf: &impl AsColumnFamilyRef,
2939 from: K,
2940 to: K,
2941 ) -> Result<(), Error> {
2942 let from = from.as_ref();
2943 let to = to.as_ref();
2944 unsafe {
2945 ffi_try!(ffi::rocksdb_delete_file_in_range_cf(
2946 self.inner.inner(),
2947 cf.inner(),
2948 from.as_ptr() as *const c_char,
2949 from.len() as size_t,
2950 to.as_ptr() as *const c_char,
2951 to.len() as size_t,
2952 ));
2953 Ok(())
2954 }
2955 }
2956
2957 pub fn cancel_all_background_work(&self, wait: bool) {
2959 unsafe {
2960 ffi::rocksdb_cancel_all_background_work(self.inner.inner(), c_uchar::from(wait));
2961 }
2962 }
2963
2964 fn drop_column_family<C>(
2965 &self,
2966 cf_inner: *mut ffi::rocksdb_column_family_handle_t,
2967 cf: C,
2968 ) -> Result<(), Error> {
2969 unsafe {
2970 ffi_try!(ffi::rocksdb_drop_column_family(
2972 self.inner.inner(),
2973 cf_inner
2974 ));
2975 }
2976 drop(cf);
2979 Ok(())
2980 }
2981
2982 pub fn increase_full_history_ts_low<S: AsRef<[u8]>>(
2987 &self,
2988 cf: &impl AsColumnFamilyRef,
2989 ts: S,
2990 ) -> Result<(), Error> {
2991 let ts = ts.as_ref();
2992 unsafe {
2993 ffi_try!(ffi::rocksdb_increase_full_history_ts_low(
2994 self.inner.inner(),
2995 cf.inner(),
2996 ts.as_ptr() as *const c_char,
2997 ts.len() as size_t,
2998 ));
2999 Ok(())
3000 }
3001 }
3002
3003 pub fn get_full_history_ts_low(&self, cf: &impl AsColumnFamilyRef) -> Result<Vec<u8>, Error> {
3005 unsafe {
3006 let mut ts_lowlen = 0;
3007 let ts = ffi_try!(ffi::rocksdb_get_full_history_ts_low(
3008 self.inner.inner(),
3009 cf.inner(),
3010 &raw mut ts_lowlen,
3011 ));
3012
3013 if ts.is_null() {
3014 Err(Error::new("Could not get full_history_ts_low".to_owned()))
3015 } else {
3016 let mut vec = vec![0; ts_lowlen];
3017 ptr::copy_nonoverlapping(ts as *mut u8, vec.as_mut_ptr(), ts_lowlen);
3018 ffi::rocksdb_free(ts as *mut c_void);
3019 Ok(vec)
3020 }
3021 }
3022 }
3023
3024 pub fn get_db_identity(&self) -> Result<Vec<u8>, Error> {
3026 unsafe {
3027 let mut length: usize = 0;
3028 let identity_ptr = ffi::rocksdb_get_db_identity(self.inner.inner(), &raw mut length);
3029 let identity_vec = raw_data(identity_ptr, length);
3030 ffi::rocksdb_free(identity_ptr as *mut c_void);
3031 identity_vec.ok_or_else(|| Error::new("get_db_identity returned NULL".to_string()))
3034 }
3035 }
3036}
3037
3038impl<I: DBInner> DBCommon<SingleThreaded, I> {
3039 pub fn create_cf<N: AsRef<str>>(&mut self, name: N, opts: &Options) -> Result<(), Error> {
3041 let inner = self.create_inner_cf_handle(name.as_ref(), opts)?;
3042 self.cfs
3043 .cfs
3044 .insert(name.as_ref().to_string(), ColumnFamily { inner });
3045 Ok(())
3046 }
3047
3048 #[doc = include_str!("db_create_column_family_with_import.md")]
3049 pub fn create_column_family_with_import<N: AsRef<str>>(
3050 &mut self,
3051 options: &Options,
3052 column_family_name: N,
3053 import_options: &ImportColumnFamilyOptions,
3054 metadata: &ExportImportFilesMetaData,
3055 ) -> Result<(), Error> {
3056 let name = column_family_name.as_ref();
3057 let c_name = CString::new(name).map_err(|err| {
3058 Error::new(format!(
3059 "Failed to convert name to CString while importing column family: {err}"
3060 ))
3061 })?;
3062 let inner = unsafe {
3063 ffi_try!(ffi::rocksdb_create_column_family_with_import(
3064 self.inner.inner(),
3065 options.inner,
3066 c_name.as_ptr(),
3067 import_options.inner,
3068 metadata.inner
3069 ))
3070 };
3071 self.cfs
3072 .cfs
3073 .insert(column_family_name.as_ref().into(), ColumnFamily { inner });
3074 Ok(())
3075 }
3076
3077 pub fn drop_cf(&mut self, name: &str) -> Result<(), Error> {
3079 match self.cfs.cfs.remove(name) {
3080 Some(cf) => self.drop_column_family(cf.inner, cf),
3081 _ => Err(Error::new(format!("Invalid column family: {name}"))),
3082 }
3083 }
3084
3085 pub fn cf_handle(&self, name: &str) -> Option<&ColumnFamily> {
3087 self.cfs.cfs.get(name)
3088 }
3089
3090 pub fn cf_names(&self) -> Vec<String> {
3094 self.cfs.cfs.keys().cloned().collect()
3095 }
3096}
3097
3098impl<I: DBInner> DBCommon<MultiThreaded, I> {
3099 pub fn create_cf<N: AsRef<str>>(&self, name: N, opts: &Options) -> Result<(), Error> {
3101 let mut cfs = self.cfs.cfs.write();
3104 let inner = self.create_inner_cf_handle(name.as_ref(), opts)?;
3105 cfs.insert(
3106 name.as_ref().to_string(),
3107 Arc::new(UnboundColumnFamily { inner }),
3108 );
3109 Ok(())
3110 }
3111
3112 #[doc = include_str!("db_create_column_family_with_import.md")]
3113 pub fn create_column_family_with_import<N: AsRef<str>>(
3114 &self,
3115 options: &Options,
3116 column_family_name: N,
3117 import_options: &ImportColumnFamilyOptions,
3118 metadata: &ExportImportFilesMetaData,
3119 ) -> Result<(), Error> {
3120 let mut cfs = self.cfs.cfs.write();
3122 let name = column_family_name.as_ref();
3123 let c_name = CString::new(name).map_err(|err| {
3124 Error::new(format!(
3125 "Failed to convert name to CString while importing column family: {err}"
3126 ))
3127 })?;
3128 let inner = unsafe {
3129 ffi_try!(ffi::rocksdb_create_column_family_with_import(
3130 self.inner.inner(),
3131 options.inner,
3132 c_name.as_ptr(),
3133 import_options.inner,
3134 metadata.inner
3135 ))
3136 };
3137 cfs.insert(
3138 column_family_name.as_ref().to_string(),
3139 Arc::new(UnboundColumnFamily { inner }),
3140 );
3141 Ok(())
3142 }
3143
3144 pub fn drop_cf(&self, name: &str) -> Result<(), Error> {
3147 match self.cfs.cfs.write().remove(name) {
3148 Some(cf) => self.drop_column_family(cf.inner, cf),
3149 _ => Err(Error::new(format!("Invalid column family: {name}"))),
3150 }
3151 }
3152
3153 pub fn cf_handle(&'_ self, name: &str) -> Option<Arc<BoundColumnFamily<'_>>> {
3155 self.cfs
3156 .cfs
3157 .read()
3158 .get(name)
3159 .cloned()
3160 .map(UnboundColumnFamily::bound_column_family)
3161 }
3162
3163 pub fn cf_names(&self) -> Vec<String> {
3167 self.cfs.cfs.read().keys().cloned().collect()
3168 }
3169}
3170
3171impl<T: ThreadMode, I: DBInner> Drop for DBCommon<T, I> {
3172 fn drop(&mut self) {
3173 self.cfs.drop_all_cfs_internal();
3174 }
3175}
3176
3177impl<T: ThreadMode, I: DBInner> fmt::Debug for DBCommon<T, I> {
3178 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3179 write!(f, "RocksDB {{ path: {} }}", self.path().display())
3180 }
3181}
3182
3183#[derive(Debug, Clone)]
3185pub struct ColumnFamilyMetaData {
3186 pub size: u64,
3189 pub name: String,
3191 pub file_count: usize,
3193}
3194
3195#[derive(Debug, Clone)]
3197pub struct LiveFile {
3198 pub column_family_name: String,
3200 pub name: String,
3202 pub directory: String,
3205 pub size: usize,
3207 pub level: i32,
3209 pub start_key: Option<Vec<u8>>,
3211 pub end_key: Option<Vec<u8>>,
3213 pub smallest_seqno: u64,
3214 pub largest_seqno: u64,
3215 pub num_entries: u64,
3217 pub num_deletions: u64,
3219}
3220
3221impl LiveFile {
3222 pub(crate) fn from_rocksdb_livefiles_ptr(
3224 files: *const ffi::rocksdb_livefiles_t,
3225 ) -> Vec<LiveFile> {
3226 unsafe {
3227 let n = ffi::rocksdb_livefiles_count(files);
3228
3229 let mut livefiles = Vec::with_capacity(n as usize);
3230 let mut key_size: usize = 0;
3231
3232 for i in 0..n {
3233 let column_family_name =
3235 from_cstr_without_free(ffi::rocksdb_livefiles_column_family_name(files, i));
3236 let name = from_cstr_without_free(ffi::rocksdb_livefiles_name(files, i));
3237 let directory = from_cstr_without_free(ffi::rocksdb_livefiles_directory(files, i));
3238 let size = ffi::rocksdb_livefiles_size(files, i);
3239 let level = ffi::rocksdb_livefiles_level(files, i);
3240
3241 let smallest_key = ffi::rocksdb_livefiles_smallestkey(files, i, &raw mut key_size);
3243 let smallest_key = raw_data(smallest_key, key_size);
3244
3245 let largest_key = ffi::rocksdb_livefiles_largestkey(files, i, &raw mut key_size);
3247 let largest_key = raw_data(largest_key, key_size);
3248
3249 livefiles.push(LiveFile {
3250 column_family_name,
3251 name,
3252 directory,
3253 size,
3254 level,
3255 start_key: smallest_key,
3256 end_key: largest_key,
3257 largest_seqno: ffi::rocksdb_livefiles_largest_seqno(files, i),
3258 smallest_seqno: ffi::rocksdb_livefiles_smallest_seqno(files, i),
3259 num_entries: ffi::rocksdb_livefiles_entries(files, i),
3260 num_deletions: ffi::rocksdb_livefiles_deletions(files, i),
3261 });
3262 }
3263
3264 livefiles
3265 }
3266 }
3267}
3268
3269struct LiveFileGuard(*mut rocksdb_livefile_t);
3270
3271impl LiveFileGuard {
3272 fn into_raw(mut self) -> *mut rocksdb_livefile_t {
3273 let ptr = self.0;
3274 self.0 = ptr::null_mut();
3275 ptr
3276 }
3277}
3278
3279impl Drop for LiveFileGuard {
3280 fn drop(&mut self) {
3281 if !self.0.is_null() {
3282 unsafe {
3283 rocksdb_livefile_destroy(self.0);
3284 }
3285 }
3286 }
3287}
3288
3289struct LiveFilesGuard(*mut rocksdb_livefiles_t);
3290
3291impl LiveFilesGuard {
3292 fn into_raw(mut self) -> *mut rocksdb_livefiles_t {
3293 let ptr = self.0;
3294 self.0 = ptr::null_mut();
3295 ptr
3296 }
3297}
3298
3299impl Drop for LiveFilesGuard {
3300 fn drop(&mut self) {
3301 if !self.0.is_null() {
3302 unsafe {
3303 rocksdb_livefiles_destroy(self.0);
3304 }
3305 }
3306 }
3307}
3308
3309#[derive(Debug)]
3314pub struct ExportImportFilesMetaData {
3315 pub(crate) inner: *mut ffi::rocksdb_export_import_files_metadata_t,
3316}
3317
3318impl ExportImportFilesMetaData {
3319 pub fn get_db_comparator_name(&self) -> String {
3320 unsafe {
3321 let c_name =
3322 ffi::rocksdb_export_import_files_metadata_get_db_comparator_name(self.inner);
3323 from_cstr_and_free(c_name)
3324 }
3325 }
3326
3327 pub fn set_db_comparator_name(&mut self, name: &str) {
3328 let c_name = CString::new(name.as_bytes()).unwrap();
3329 unsafe {
3330 ffi::rocksdb_export_import_files_metadata_set_db_comparator_name(
3331 self.inner,
3332 c_name.as_ptr(),
3333 );
3334 };
3335 }
3336
3337 pub fn get_files(&self) -> Vec<LiveFile> {
3338 unsafe {
3339 let livefiles_ptr = ffi::rocksdb_export_import_files_metadata_get_files(self.inner);
3340 let files = LiveFile::from_rocksdb_livefiles_ptr(livefiles_ptr);
3341 ffi::rocksdb_livefiles_destroy(livefiles_ptr);
3342 files
3343 }
3344 }
3345
3346 pub fn set_files(&mut self, files: &[LiveFile]) -> Result<(), Error> {
3347 static EMPTY: [u8; 0] = [];
3349 let empty_ptr = EMPTY.as_ptr() as *const libc::c_char;
3350
3351 unsafe {
3352 let live_files = LiveFilesGuard(ffi::rocksdb_livefiles_create());
3353
3354 for file in files {
3355 let live_file = LiveFileGuard(ffi::rocksdb_livefile_create());
3356 ffi::rocksdb_livefile_set_level(live_file.0, file.level);
3357
3358 let c_cf_name = CString::new(file.column_family_name.as_str()).map_err(|err| {
3360 Error::new(format!("Unable to convert column family to CString: {err}"))
3361 })?;
3362 ffi::rocksdb_livefile_set_column_family_name(live_file.0, c_cf_name.as_ptr());
3363
3364 let c_name = CString::new(file.name.as_str()).map_err(|err| {
3365 Error::new(format!("Unable to convert file name to CString: {err}"))
3366 })?;
3367 ffi::rocksdb_livefile_set_name(live_file.0, c_name.as_ptr());
3368
3369 let c_directory = CString::new(file.directory.as_str()).map_err(|err| {
3370 Error::new(format!("Unable to convert directory to CString: {err}"))
3371 })?;
3372 ffi::rocksdb_livefile_set_directory(live_file.0, c_directory.as_ptr());
3373
3374 ffi::rocksdb_livefile_set_size(live_file.0, file.size);
3375
3376 let (start_key_ptr, start_key_len) = match &file.start_key {
3377 None => (empty_ptr, 0),
3378 Some(key) => (key.as_ptr() as *const libc::c_char, key.len()),
3379 };
3380 ffi::rocksdb_livefile_set_smallest_key(live_file.0, start_key_ptr, start_key_len);
3381
3382 let (largest_key_ptr, largest_key_len) = match &file.end_key {
3383 None => (empty_ptr, 0),
3384 Some(key) => (key.as_ptr() as *const libc::c_char, key.len()),
3385 };
3386 ffi::rocksdb_livefile_set_largest_key(
3387 live_file.0,
3388 largest_key_ptr,
3389 largest_key_len,
3390 );
3391 ffi::rocksdb_livefile_set_smallest_seqno(live_file.0, file.smallest_seqno);
3392 ffi::rocksdb_livefile_set_largest_seqno(live_file.0, file.largest_seqno);
3393 ffi::rocksdb_livefile_set_num_entries(live_file.0, file.num_entries);
3394 ffi::rocksdb_livefile_set_num_deletions(live_file.0, file.num_deletions);
3395
3396 ffi::rocksdb_livefiles_add(live_files.0, live_file.into_raw());
3398 }
3399
3400 ffi::rocksdb_export_import_files_metadata_set_files(self.inner, live_files.into_raw());
3402 Ok(())
3403 }
3404 }
3405}
3406
3407impl Default for ExportImportFilesMetaData {
3408 fn default() -> Self {
3409 let inner = unsafe { ffi::rocksdb_export_import_files_metadata_create() };
3410 assert!(
3411 !inner.is_null(),
3412 "Could not create rocksdb_export_import_files_metadata_t"
3413 );
3414
3415 Self { inner }
3416 }
3417}
3418
3419impl Drop for ExportImportFilesMetaData {
3420 fn drop(&mut self) {
3421 unsafe {
3422 ffi::rocksdb_export_import_files_metadata_destroy(self.inner);
3423 }
3424 }
3425}
3426
3427unsafe impl Send for ExportImportFilesMetaData {}
3428unsafe impl Sync for ExportImportFilesMetaData {}
3429
3430fn convert_options(opts: &[(&str, &str)]) -> Result<Vec<(CString, CString)>, Error> {
3431 opts.iter()
3432 .map(|(name, value)| {
3433 let cname = match CString::new(name.as_bytes()) {
3434 Ok(cname) => cname,
3435 Err(e) => return Err(Error::new(format!("Invalid option name `{e}`"))),
3436 };
3437 let cvalue = match CString::new(value.as_bytes()) {
3438 Ok(cvalue) => cvalue,
3439 Err(e) => return Err(Error::new(format!("Invalid option value: `{e}`"))),
3440 };
3441 Ok((cname, cvalue))
3442 })
3443 .collect()
3444}
3445
3446pub(crate) fn convert_values(
3447 values: Vec<*mut c_char>,
3448 values_sizes: Vec<usize>,
3449 errors: Vec<*mut c_char>,
3450) -> Vec<Result<Option<Vec<u8>>, Error>> {
3451 values
3452 .into_iter()
3453 .zip(values_sizes)
3454 .zip(errors)
3455 .map(|((v, s), e)| {
3456 if e.is_null() {
3457 let value = unsafe { crate::ffi_util::raw_data(v, s) };
3458 unsafe {
3459 ffi::rocksdb_free(v as *mut c_void);
3460 }
3461 Ok(value)
3462 } else {
3463 Err(convert_rocksdb_error(e))
3464 }
3465 })
3466 .collect()
3467}