rocksdb/
db.rs

1// Copyright 2020 Tyler Neely
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14//
15
16use crate::{
17    column_family::AsColumnFamilyRef,
18    column_family::BoundColumnFamily,
19    column_family::UnboundColumnFamily,
20    db_options::OptionsMustOutliveDB,
21    ffi,
22    ffi_util::{from_cstr, opt_bytes_to_ptr, raw_data, to_cpath, CStrLike},
23    ColumnFamily, ColumnFamilyDescriptor, CompactOptions, DBIteratorWithThreadMode,
24    DBPinnableSlice, DBRawIteratorWithThreadMode, DBWALIterator, Direction, Error, FlushOptions,
25    IngestExternalFileOptions, IteratorMode, Options, ReadOptions, SnapshotWithThreadMode,
26    WaitForCompactOptions, WriteBatch, WriteOptions, DEFAULT_COLUMN_FAMILY_NAME,
27};
28
29use crate::column_family::ColumnFamilyTtl;
30use crate::ffi_util::CSlice;
31use libc::{self, c_char, c_int, c_uchar, c_void, size_t};
32use std::collections::BTreeMap;
33use std::ffi::{CStr, CString};
34use std::fmt;
35use std::fs;
36use std::iter;
37use std::path::Path;
38use std::path::PathBuf;
39use std::ptr;
40use std::slice;
41use std::str;
42use std::sync::Arc;
43use std::sync::RwLock;
44use std::time::Duration;
45
46/// A range of keys, `start_key` is included, but not `end_key`.
47///
48/// You should make sure `end_key` is not less than `start_key`.
49pub struct Range<'a> {
50    start_key: &'a [u8],
51    end_key: &'a [u8],
52}
53
54impl<'a> Range<'a> {
55    pub fn new(start_key: &'a [u8], end_key: &'a [u8]) -> Range<'a> {
56        Range { start_key, end_key }
57    }
58}
59
60/// Marker trait to specify single or multi threaded column family alternations for
61/// [`DBWithThreadMode<T>`]
62///
63/// This arrangement makes differences in self mutability and return type in
64/// some of `DBWithThreadMode` methods.
65///
66/// While being a marker trait to be generic over `DBWithThreadMode`, this trait
67/// also has a minimum set of not-encapsulated internal methods between
68/// [`SingleThreaded`] and [`MultiThreaded`].  These methods aren't expected to be
69/// called and defined externally.
70pub trait ThreadMode {
71    /// Internal implementation for storing column family handles
72    fn new_cf_map_internal(
73        cf_map: BTreeMap<String, *mut ffi::rocksdb_column_family_handle_t>,
74    ) -> Self;
75    /// Internal implementation for dropping column family handles
76    fn drop_all_cfs_internal(&mut self);
77}
78
79/// Actual marker type for the marker trait `ThreadMode`, which holds
80/// a collection of column families without synchronization primitive, providing
81/// no overhead for the single-threaded column family alternations. The other
82/// mode is [`MultiThreaded`].
83///
84/// See [`DB`] for more details, including performance implications for each mode
85pub struct SingleThreaded {
86    pub(crate) cfs: BTreeMap<String, ColumnFamily>,
87}
88
89/// Actual marker type for the marker trait `ThreadMode`, which holds
90/// a collection of column families wrapped in a RwLock to be mutated
91/// concurrently. The other mode is [`SingleThreaded`].
92///
93/// See [`DB`] for more details, including performance implications for each mode
94pub struct MultiThreaded {
95    pub(crate) cfs: RwLock<BTreeMap<String, Arc<UnboundColumnFamily>>>,
96}
97
98impl ThreadMode for SingleThreaded {
99    fn new_cf_map_internal(
100        cfs: BTreeMap<String, *mut ffi::rocksdb_column_family_handle_t>,
101    ) -> Self {
102        Self {
103            cfs: cfs
104                .into_iter()
105                .map(|(n, c)| (n, ColumnFamily { inner: c }))
106                .collect(),
107        }
108    }
109
110    fn drop_all_cfs_internal(&mut self) {
111        // Cause all ColumnFamily objects to be Drop::drop()-ed.
112        self.cfs.clear();
113    }
114}
115
116impl ThreadMode for MultiThreaded {
117    fn new_cf_map_internal(
118        cfs: BTreeMap<String, *mut ffi::rocksdb_column_family_handle_t>,
119    ) -> Self {
120        Self {
121            cfs: RwLock::new(
122                cfs.into_iter()
123                    .map(|(n, c)| (n, Arc::new(UnboundColumnFamily { inner: c })))
124                    .collect(),
125            ),
126        }
127    }
128
129    fn drop_all_cfs_internal(&mut self) {
130        // Cause all UnboundColumnFamily objects to be Drop::drop()-ed.
131        self.cfs.write().unwrap().clear();
132    }
133}
134
135/// Get underlying `rocksdb_t`.
136pub trait DBInner {
137    fn inner(&self) -> *mut ffi::rocksdb_t;
138}
139
140/// A helper type to implement some common methods for [`DBWithThreadMode`]
141/// and [`OptimisticTransactionDB`].
142///
143/// [`OptimisticTransactionDB`]: crate::OptimisticTransactionDB
144pub struct DBCommon<T: ThreadMode, D: DBInner> {
145    pub(crate) inner: D,
146    cfs: T, // Column families are held differently depending on thread mode
147    path: PathBuf,
148    _outlive: Vec<OptionsMustOutliveDB>,
149}
150
151/// Minimal set of DB-related methods, intended to be generic over
152/// `DBWithThreadMode<T>`. Mainly used internally
153pub trait DBAccess {
154    unsafe fn create_snapshot(&self) -> *const ffi::rocksdb_snapshot_t;
155
156    unsafe fn release_snapshot(&self, snapshot: *const ffi::rocksdb_snapshot_t);
157
158    unsafe fn create_iterator(&self, readopts: &ReadOptions) -> *mut ffi::rocksdb_iterator_t;
159
160    unsafe fn create_iterator_cf(
161        &self,
162        cf_handle: *mut ffi::rocksdb_column_family_handle_t,
163        readopts: &ReadOptions,
164    ) -> *mut ffi::rocksdb_iterator_t;
165
166    fn get_opt<K: AsRef<[u8]>>(
167        &self,
168        key: K,
169        readopts: &ReadOptions,
170    ) -> Result<Option<Vec<u8>>, Error>;
171
172    fn get_cf_opt<K: AsRef<[u8]>>(
173        &self,
174        cf: &impl AsColumnFamilyRef,
175        key: K,
176        readopts: &ReadOptions,
177    ) -> Result<Option<Vec<u8>>, Error>;
178
179    fn get_pinned_opt<K: AsRef<[u8]>>(
180        &self,
181        key: K,
182        readopts: &ReadOptions,
183    ) -> Result<Option<DBPinnableSlice>, Error>;
184
185    fn get_pinned_cf_opt<K: AsRef<[u8]>>(
186        &self,
187        cf: &impl AsColumnFamilyRef,
188        key: K,
189        readopts: &ReadOptions,
190    ) -> Result<Option<DBPinnableSlice>, Error>;
191
192    fn multi_get_opt<K, I>(
193        &self,
194        keys: I,
195        readopts: &ReadOptions,
196    ) -> Vec<Result<Option<Vec<u8>>, Error>>
197    where
198        K: AsRef<[u8]>,
199        I: IntoIterator<Item = K>;
200
201    fn multi_get_cf_opt<'b, K, I, W>(
202        &self,
203        keys_cf: I,
204        readopts: &ReadOptions,
205    ) -> Vec<Result<Option<Vec<u8>>, Error>>
206    where
207        K: AsRef<[u8]>,
208        I: IntoIterator<Item = (&'b W, K)>,
209        W: AsColumnFamilyRef + 'b;
210}
211
212impl<T: ThreadMode, D: DBInner> DBAccess for DBCommon<T, D> {
213    unsafe fn create_snapshot(&self) -> *const ffi::rocksdb_snapshot_t {
214        unsafe { ffi::rocksdb_create_snapshot(self.inner.inner()) }
215    }
216
217    unsafe fn release_snapshot(&self, snapshot: *const ffi::rocksdb_snapshot_t) {
218        unsafe { ffi::rocksdb_release_snapshot(self.inner.inner(), snapshot) };
219    }
220
221    unsafe fn create_iterator(&self, readopts: &ReadOptions) -> *mut ffi::rocksdb_iterator_t {
222        unsafe { ffi::rocksdb_create_iterator(self.inner.inner(), readopts.inner) }
223    }
224
225    unsafe fn create_iterator_cf(
226        &self,
227        cf_handle: *mut ffi::rocksdb_column_family_handle_t,
228        readopts: &ReadOptions,
229    ) -> *mut ffi::rocksdb_iterator_t {
230        unsafe { ffi::rocksdb_create_iterator_cf(self.inner.inner(), readopts.inner, cf_handle) }
231    }
232
233    fn get_opt<K: AsRef<[u8]>>(
234        &self,
235        key: K,
236        readopts: &ReadOptions,
237    ) -> Result<Option<Vec<u8>>, Error> {
238        self.get_opt(key, readopts)
239    }
240
241    fn get_cf_opt<K: AsRef<[u8]>>(
242        &self,
243        cf: &impl AsColumnFamilyRef,
244        key: K,
245        readopts: &ReadOptions,
246    ) -> Result<Option<Vec<u8>>, Error> {
247        self.get_cf_opt(cf, key, readopts)
248    }
249
250    fn get_pinned_opt<K: AsRef<[u8]>>(
251        &self,
252        key: K,
253        readopts: &ReadOptions,
254    ) -> Result<Option<DBPinnableSlice>, Error> {
255        self.get_pinned_opt(key, readopts)
256    }
257
258    fn get_pinned_cf_opt<K: AsRef<[u8]>>(
259        &self,
260        cf: &impl AsColumnFamilyRef,
261        key: K,
262        readopts: &ReadOptions,
263    ) -> Result<Option<DBPinnableSlice>, Error> {
264        self.get_pinned_cf_opt(cf, key, readopts)
265    }
266
267    fn multi_get_opt<K, Iter>(
268        &self,
269        keys: Iter,
270        readopts: &ReadOptions,
271    ) -> Vec<Result<Option<Vec<u8>>, Error>>
272    where
273        K: AsRef<[u8]>,
274        Iter: IntoIterator<Item = K>,
275    {
276        self.multi_get_opt(keys, readopts)
277    }
278
279    fn multi_get_cf_opt<'b, K, Iter, W>(
280        &self,
281        keys_cf: Iter,
282        readopts: &ReadOptions,
283    ) -> Vec<Result<Option<Vec<u8>>, Error>>
284    where
285        K: AsRef<[u8]>,
286        Iter: IntoIterator<Item = (&'b W, K)>,
287        W: AsColumnFamilyRef + 'b,
288    {
289        self.multi_get_cf_opt(keys_cf, readopts)
290    }
291}
292
293pub struct DBWithThreadModeInner {
294    inner: *mut ffi::rocksdb_t,
295}
296
297impl DBInner for DBWithThreadModeInner {
298    fn inner(&self) -> *mut ffi::rocksdb_t {
299        self.inner
300    }
301}
302
303impl Drop for DBWithThreadModeInner {
304    fn drop(&mut self) {
305        unsafe {
306            ffi::rocksdb_close(self.inner);
307        }
308    }
309}
310
311/// A type alias to RocksDB database.
312///
313/// See crate level documentation for a simple usage example.
314/// See [`DBCommon`] for full list of methods.
315pub type DBWithThreadMode<T> = DBCommon<T, DBWithThreadModeInner>;
316
317/// A type alias to DB instance type with the single-threaded column family
318/// creations/deletions
319///
320/// # Compatibility and multi-threaded mode
321///
322/// Previously, [`DB`] was defined as a direct `struct`. Now, it's type-aliased for
323/// compatibility. Use `DBCommon<MultiThreaded>` for multi-threaded
324/// column family alternations.
325///
326/// # Limited performance implication for single-threaded mode
327///
328/// Even with [`SingleThreaded`], almost all of RocksDB operations is
329/// multi-threaded unless the underlying RocksDB instance is
330/// specifically configured otherwise. `SingleThreaded` only forces
331/// serialization of column family alternations by requiring `&mut self` of DB
332/// instance due to its wrapper implementation details.
333///
334/// # Multi-threaded mode
335///
336/// [`MultiThreaded`] can be appropriate for the situation of multi-threaded
337/// workload including multi-threaded column family alternations, costing the
338/// RwLock overhead inside `DB`.
339#[cfg(not(feature = "multi-threaded-cf"))]
340pub type DB = DBWithThreadMode<SingleThreaded>;
341
342#[cfg(feature = "multi-threaded-cf")]
343pub type DB = DBWithThreadMode<MultiThreaded>;
344
345// Safety note: auto-implementing Send on most db-related types is prevented by the inner FFI
346// pointer. In most cases, however, this pointer is Send-safe because it is never aliased and
347// rocksdb internally does not rely on thread-local information for its user-exposed types.
348unsafe impl<T: ThreadMode + Send, I: DBInner> Send for DBCommon<T, I> {}
349
350// Sync is similarly safe for many types because they do not expose interior mutability, and their
351// use within the rocksdb library is generally behind a const reference
352unsafe impl<T: ThreadMode, I: DBInner> Sync for DBCommon<T, I> {}
353
354// Specifies whether open DB for read only.
355enum AccessType<'a> {
356    ReadWrite,
357    ReadOnly { error_if_log_file_exist: bool },
358    Secondary { secondary_path: &'a Path },
359    WithTTL { ttl: Duration },
360}
361
362/// Methods of `DBWithThreadMode`.
363impl<T: ThreadMode> DBWithThreadMode<T> {
364    /// Opens a database with default options.
365    pub fn open_default<P: AsRef<Path>>(path: P) -> Result<Self, Error> {
366        let mut opts = Options::default();
367        opts.create_if_missing(true);
368        Self::open(&opts, path)
369    }
370
371    /// Opens the database with the specified options.
372    pub fn open<P: AsRef<Path>>(opts: &Options, path: P) -> Result<Self, Error> {
373        Self::open_cf(opts, path, None::<&str>)
374    }
375
376    /// Opens the database for read only with the specified options.
377    pub fn open_for_read_only<P: AsRef<Path>>(
378        opts: &Options,
379        path: P,
380        error_if_log_file_exist: bool,
381    ) -> Result<Self, Error> {
382        Self::open_cf_for_read_only(opts, path, None::<&str>, error_if_log_file_exist)
383    }
384
385    /// Opens the database as a secondary.
386    pub fn open_as_secondary<P: AsRef<Path>>(
387        opts: &Options,
388        primary_path: P,
389        secondary_path: P,
390    ) -> Result<Self, Error> {
391        Self::open_cf_as_secondary(opts, primary_path, secondary_path, None::<&str>)
392    }
393
394    /// Opens the database with a Time to Live compaction filter.
395    ///
396    /// This applies the given `ttl` to all column families created without an explicit TTL.
397    /// See [`DB::open_cf_descriptors_with_ttl`] for more control over individual column family TTLs.
398    pub fn open_with_ttl<P: AsRef<Path>>(
399        opts: &Options,
400        path: P,
401        ttl: Duration,
402    ) -> Result<Self, Error> {
403        Self::open_cf_descriptors_with_ttl(opts, path, std::iter::empty(), ttl)
404    }
405
406    /// Opens the database with a Time to Live compaction filter and column family names.
407    ///
408    /// Column families opened using this function will be created with default `Options`.
409    pub fn open_cf_with_ttl<P, I, N>(
410        opts: &Options,
411        path: P,
412        cfs: I,
413        ttl: Duration,
414    ) -> Result<Self, Error>
415    where
416        P: AsRef<Path>,
417        I: IntoIterator<Item = N>,
418        N: AsRef<str>,
419    {
420        let cfs = cfs
421            .into_iter()
422            .map(|name| ColumnFamilyDescriptor::new(name.as_ref(), Options::default()));
423
424        Self::open_cf_descriptors_with_ttl(opts, path, cfs, ttl)
425    }
426
427    /// Opens a database with the given database with a Time to Live compaction filter and
428    /// column family descriptors.
429    ///
430    /// Applies the provided `ttl` as the default TTL for all column families.
431    /// Column families will inherit this TTL by default, unless their descriptor explicitly
432    /// sets a different TTL using [`ColumnFamilyTtl::Duration`] or opts out using [`ColumnFamilyTtl::Disabled`].
433    ///
434    /// *NOTE*: The `default` column family is opened with `Options::default()` unless
435    /// explicitly configured within the `cfs` iterator.
436    /// To customize the `default` column family's options, include a `ColumnFamilyDescriptor`
437    /// with the name "default" in the `cfs` iterator.
438    ///
439    /// If you want to open `default` cf with different options, set them explicitly in `cfs`.
440    pub fn open_cf_descriptors_with_ttl<P, I>(
441        opts: &Options,
442        path: P,
443        cfs: I,
444        ttl: Duration,
445    ) -> Result<Self, Error>
446    where
447        P: AsRef<Path>,
448        I: IntoIterator<Item = ColumnFamilyDescriptor>,
449    {
450        Self::open_cf_descriptors_internal(opts, path, cfs, &AccessType::WithTTL { ttl })
451    }
452
453    /// Opens a database with the given database options and column family names.
454    ///
455    /// Column families opened using this function will be created with default `Options`.
456    pub fn open_cf<P, I, N>(opts: &Options, path: P, cfs: I) -> Result<Self, Error>
457    where
458        P: AsRef<Path>,
459        I: IntoIterator<Item = N>,
460        N: AsRef<str>,
461    {
462        let cfs = cfs
463            .into_iter()
464            .map(|name| ColumnFamilyDescriptor::new(name.as_ref(), Options::default()));
465
466        Self::open_cf_descriptors_internal(opts, path, cfs, &AccessType::ReadWrite)
467    }
468
469    /// Opens a database with the given database options and column family names.
470    ///
471    /// Column families opened using given `Options`.
472    pub fn open_cf_with_opts<P, I, N>(opts: &Options, path: P, cfs: I) -> Result<Self, Error>
473    where
474        P: AsRef<Path>,
475        I: IntoIterator<Item = (N, Options)>,
476        N: AsRef<str>,
477    {
478        let cfs = cfs
479            .into_iter()
480            .map(|(name, opts)| ColumnFamilyDescriptor::new(name.as_ref(), opts));
481
482        Self::open_cf_descriptors(opts, path, cfs)
483    }
484
485    /// Opens a database for read only with the given database options and column family names.
486    /// *NOTE*: `default` column family is opened with `Options::default()`.
487    /// If you want to open `default` cf with different options, set them explicitly in `cfs`.
488    pub fn open_cf_for_read_only<P, I, N>(
489        opts: &Options,
490        path: P,
491        cfs: I,
492        error_if_log_file_exist: bool,
493    ) -> Result<Self, Error>
494    where
495        P: AsRef<Path>,
496        I: IntoIterator<Item = N>,
497        N: AsRef<str>,
498    {
499        let cfs = cfs
500            .into_iter()
501            .map(|name| ColumnFamilyDescriptor::new(name.as_ref(), Options::default()));
502
503        Self::open_cf_descriptors_internal(
504            opts,
505            path,
506            cfs,
507            &AccessType::ReadOnly {
508                error_if_log_file_exist,
509            },
510        )
511    }
512
513    /// Opens a database for read only with the given database options and column family names.
514    /// *NOTE*: `default` column family is opened with `Options::default()`.
515    /// If you want to open `default` cf with different options, set them explicitly in `cfs`.
516    pub fn open_cf_with_opts_for_read_only<P, I, N>(
517        db_opts: &Options,
518        path: P,
519        cfs: I,
520        error_if_log_file_exist: bool,
521    ) -> Result<Self, Error>
522    where
523        P: AsRef<Path>,
524        I: IntoIterator<Item = (N, Options)>,
525        N: AsRef<str>,
526    {
527        let cfs = cfs
528            .into_iter()
529            .map(|(name, cf_opts)| ColumnFamilyDescriptor::new(name.as_ref(), cf_opts));
530
531        Self::open_cf_descriptors_internal(
532            db_opts,
533            path,
534            cfs,
535            &AccessType::ReadOnly {
536                error_if_log_file_exist,
537            },
538        )
539    }
540
541    /// Opens a database for ready only with the given database options and
542    /// column family descriptors.
543    /// *NOTE*: `default` column family is opened with `Options::default()`.
544    /// If you want to open `default` cf with different options, set them explicitly in `cfs`.
545    pub fn open_cf_descriptors_read_only<P, I>(
546        opts: &Options,
547        path: P,
548        cfs: I,
549        error_if_log_file_exist: bool,
550    ) -> Result<Self, Error>
551    where
552        P: AsRef<Path>,
553        I: IntoIterator<Item = ColumnFamilyDescriptor>,
554    {
555        Self::open_cf_descriptors_internal(
556            opts,
557            path,
558            cfs,
559            &AccessType::ReadOnly {
560                error_if_log_file_exist,
561            },
562        )
563    }
564
565    /// Opens the database as a secondary with the given database options and column family names.
566    /// *NOTE*: `default` column family is opened with `Options::default()`.
567    /// If you want to open `default` cf with different options, set them explicitly in `cfs`.
568    pub fn open_cf_as_secondary<P, I, N>(
569        opts: &Options,
570        primary_path: P,
571        secondary_path: P,
572        cfs: I,
573    ) -> Result<Self, Error>
574    where
575        P: AsRef<Path>,
576        I: IntoIterator<Item = N>,
577        N: AsRef<str>,
578    {
579        let cfs = cfs
580            .into_iter()
581            .map(|name| ColumnFamilyDescriptor::new(name.as_ref(), Options::default()));
582
583        Self::open_cf_descriptors_internal(
584            opts,
585            primary_path,
586            cfs,
587            &AccessType::Secondary {
588                secondary_path: secondary_path.as_ref(),
589            },
590        )
591    }
592
593    /// Opens the database as a secondary with the given database options and
594    /// column family descriptors.
595    /// *NOTE*: `default` column family is opened with `Options::default()`.
596    /// If you want to open `default` cf with different options, set them explicitly in `cfs`.
597    pub fn open_cf_descriptors_as_secondary<P, I>(
598        opts: &Options,
599        path: P,
600        secondary_path: P,
601        cfs: I,
602    ) -> Result<Self, Error>
603    where
604        P: AsRef<Path>,
605        I: IntoIterator<Item = ColumnFamilyDescriptor>,
606    {
607        Self::open_cf_descriptors_internal(
608            opts,
609            path,
610            cfs,
611            &AccessType::Secondary {
612                secondary_path: secondary_path.as_ref(),
613            },
614        )
615    }
616
617    /// Opens a database with the given database options and column family descriptors.
618    /// *NOTE*: `default` column family is opened with `Options::default()`.
619    /// If you want to open `default` cf with different options, set them explicitly in `cfs`.
620    pub fn open_cf_descriptors<P, I>(opts: &Options, path: P, cfs: I) -> Result<Self, Error>
621    where
622        P: AsRef<Path>,
623        I: IntoIterator<Item = ColumnFamilyDescriptor>,
624    {
625        Self::open_cf_descriptors_internal(opts, path, cfs, &AccessType::ReadWrite)
626    }
627
628    /// Internal implementation for opening RocksDB.
629    fn open_cf_descriptors_internal<P, I>(
630        opts: &Options,
631        path: P,
632        cfs: I,
633        access_type: &AccessType,
634    ) -> Result<Self, Error>
635    where
636        P: AsRef<Path>,
637        I: IntoIterator<Item = ColumnFamilyDescriptor>,
638    {
639        let cfs: Vec<_> = cfs.into_iter().collect();
640        let outlive = iter::once(opts.outlive.clone())
641            .chain(cfs.iter().map(|cf| cf.options.outlive.clone()))
642            .collect();
643
644        let cpath = to_cpath(&path)?;
645
646        if let Err(e) = fs::create_dir_all(&path) {
647            return Err(Error::new(format!(
648                "Failed to create RocksDB directory: `{e:?}`."
649            )));
650        }
651
652        let db: *mut ffi::rocksdb_t;
653        let mut cf_map = BTreeMap::new();
654
655        if cfs.is_empty() {
656            db = Self::open_raw(opts, &cpath, access_type)?;
657        } else {
658            let mut cfs_v = cfs;
659            // Always open the default column family.
660            if !cfs_v.iter().any(|cf| cf.name == DEFAULT_COLUMN_FAMILY_NAME) {
661                cfs_v.push(ColumnFamilyDescriptor {
662                    name: String::from(DEFAULT_COLUMN_FAMILY_NAME),
663                    options: Options::default(),
664                    ttl: ColumnFamilyTtl::SameAsDb,
665                });
666            }
667            // We need to store our CStrings in an intermediate vector
668            // so that their pointers remain valid.
669            let c_cfs: Vec<CString> = cfs_v
670                .iter()
671                .map(|cf| CString::new(cf.name.as_bytes()).unwrap())
672                .collect();
673
674            let cfnames: Vec<_> = c_cfs.iter().map(|cf| cf.as_ptr()).collect();
675
676            // These handles will be populated by DB.
677            let mut cfhandles: Vec<_> = cfs_v.iter().map(|_| ptr::null_mut()).collect();
678
679            let cfopts: Vec<_> = cfs_v
680                .iter()
681                .map(|cf| cf.options.inner.cast_const())
682                .collect();
683
684            db = Self::open_cf_raw(
685                opts,
686                &cpath,
687                &cfs_v,
688                &cfnames,
689                &cfopts,
690                &mut cfhandles,
691                access_type,
692            )?;
693            for handle in &cfhandles {
694                if handle.is_null() {
695                    return Err(Error::new(
696                        "Received null column family handle from DB.".to_owned(),
697                    ));
698                }
699            }
700
701            for (cf_desc, inner) in cfs_v.iter().zip(cfhandles) {
702                cf_map.insert(cf_desc.name.clone(), inner);
703            }
704        }
705
706        if db.is_null() {
707            return Err(Error::new("Could not initialize database.".to_owned()));
708        }
709
710        Ok(Self {
711            inner: DBWithThreadModeInner { inner: db },
712            path: path.as_ref().to_path_buf(),
713            cfs: T::new_cf_map_internal(cf_map),
714            _outlive: outlive,
715        })
716    }
717
718    fn open_raw(
719        opts: &Options,
720        cpath: &CString,
721        access_type: &AccessType,
722    ) -> Result<*mut ffi::rocksdb_t, Error> {
723        let db = unsafe {
724            match *access_type {
725                AccessType::ReadOnly {
726                    error_if_log_file_exist,
727                } => ffi_try!(ffi::rocksdb_open_for_read_only(
728                    opts.inner,
729                    cpath.as_ptr(),
730                    c_uchar::from(error_if_log_file_exist),
731                )),
732                AccessType::ReadWrite => {
733                    ffi_try!(ffi::rocksdb_open(opts.inner, cpath.as_ptr()))
734                }
735                AccessType::Secondary { secondary_path } => {
736                    ffi_try!(ffi::rocksdb_open_as_secondary(
737                        opts.inner,
738                        cpath.as_ptr(),
739                        to_cpath(secondary_path)?.as_ptr(),
740                    ))
741                }
742                AccessType::WithTTL { ttl } => ffi_try!(ffi::rocksdb_open_with_ttl(
743                    opts.inner,
744                    cpath.as_ptr(),
745                    ttl.as_secs() as c_int,
746                )),
747            }
748        };
749        Ok(db)
750    }
751
752    #[allow(clippy::pedantic)]
753    fn open_cf_raw(
754        opts: &Options,
755        cpath: &CString,
756        cfs_v: &[ColumnFamilyDescriptor],
757        cfnames: &[*const c_char],
758        cfopts: &[*const ffi::rocksdb_options_t],
759        cfhandles: &mut [*mut ffi::rocksdb_column_family_handle_t],
760        access_type: &AccessType,
761    ) -> Result<*mut ffi::rocksdb_t, Error> {
762        let db = unsafe {
763            match *access_type {
764                AccessType::ReadOnly {
765                    error_if_log_file_exist,
766                } => ffi_try!(ffi::rocksdb_open_for_read_only_column_families(
767                    opts.inner,
768                    cpath.as_ptr(),
769                    cfs_v.len() as c_int,
770                    cfnames.as_ptr(),
771                    cfopts.as_ptr(),
772                    cfhandles.as_mut_ptr(),
773                    c_uchar::from(error_if_log_file_exist),
774                )),
775                AccessType::ReadWrite => ffi_try!(ffi::rocksdb_open_column_families(
776                    opts.inner,
777                    cpath.as_ptr(),
778                    cfs_v.len() as c_int,
779                    cfnames.as_ptr(),
780                    cfopts.as_ptr(),
781                    cfhandles.as_mut_ptr(),
782                )),
783                AccessType::Secondary { secondary_path } => {
784                    ffi_try!(ffi::rocksdb_open_as_secondary_column_families(
785                        opts.inner,
786                        cpath.as_ptr(),
787                        to_cpath(secondary_path)?.as_ptr(),
788                        cfs_v.len() as c_int,
789                        cfnames.as_ptr(),
790                        cfopts.as_ptr(),
791                        cfhandles.as_mut_ptr(),
792                    ))
793                }
794                AccessType::WithTTL { ttl } => {
795                    let ttls: Vec<_> = cfs_v
796                        .iter()
797                        .map(|cf| match cf.ttl {
798                            ColumnFamilyTtl::Disabled => i32::MAX,
799                            ColumnFamilyTtl::Duration(duration) => duration.as_secs() as i32,
800                            ColumnFamilyTtl::SameAsDb => ttl.as_secs() as i32,
801                        })
802                        .collect();
803
804                    ffi_try!(ffi::rocksdb_open_column_families_with_ttl(
805                        opts.inner,
806                        cpath.as_ptr(),
807                        cfs_v.len() as c_int,
808                        cfnames.as_ptr(),
809                        cfopts.as_ptr(),
810                        cfhandles.as_mut_ptr(),
811                        ttls.as_ptr(),
812                    ))
813                }
814            }
815        };
816        Ok(db)
817    }
818
819    /// Removes the database entries in the range `["from", "to")` using given write options.
820    pub fn delete_range_cf_opt<K: AsRef<[u8]>>(
821        &self,
822        cf: &impl AsColumnFamilyRef,
823        from: K,
824        to: K,
825        writeopts: &WriteOptions,
826    ) -> Result<(), Error> {
827        let from = from.as_ref();
828        let to = to.as_ref();
829
830        unsafe {
831            ffi_try!(ffi::rocksdb_delete_range_cf(
832                self.inner.inner(),
833                writeopts.inner,
834                cf.inner(),
835                from.as_ptr() as *const c_char,
836                from.len() as size_t,
837                to.as_ptr() as *const c_char,
838                to.len() as size_t,
839            ));
840            Ok(())
841        }
842    }
843
844    /// Removes the database entries in the range `["from", "to")` using default write options.
845    pub fn delete_range_cf<K: AsRef<[u8]>>(
846        &self,
847        cf: &impl AsColumnFamilyRef,
848        from: K,
849        to: K,
850    ) -> Result<(), Error> {
851        self.delete_range_cf_opt(cf, from, to, &WriteOptions::default())
852    }
853
854    pub fn write_opt(&self, batch: WriteBatch, writeopts: &WriteOptions) -> Result<(), Error> {
855        unsafe {
856            ffi_try!(ffi::rocksdb_write(
857                self.inner.inner(),
858                writeopts.inner,
859                batch.inner
860            ));
861        }
862        Ok(())
863    }
864
865    pub fn write(&self, batch: WriteBatch) -> Result<(), Error> {
866        self.write_opt(batch, &WriteOptions::default())
867    }
868
869    pub fn write_without_wal(&self, batch: WriteBatch) -> Result<(), Error> {
870        let mut wo = WriteOptions::new();
871        wo.disable_wal(true);
872        self.write_opt(batch, &wo)
873    }
874}
875
876/// Common methods of `DBWithThreadMode` and `OptimisticTransactionDB`.
877impl<T: ThreadMode, D: DBInner> DBCommon<T, D> {
878    pub(crate) fn new(inner: D, cfs: T, path: PathBuf, outlive: Vec<OptionsMustOutliveDB>) -> Self {
879        Self {
880            inner,
881            cfs,
882            path,
883            _outlive: outlive,
884        }
885    }
886
887    pub fn list_cf<P: AsRef<Path>>(opts: &Options, path: P) -> Result<Vec<String>, Error> {
888        let cpath = to_cpath(path)?;
889        let mut length = 0;
890
891        unsafe {
892            let ptr = ffi_try!(ffi::rocksdb_list_column_families(
893                opts.inner,
894                cpath.as_ptr(),
895                &mut length,
896            ));
897
898            let vec = slice::from_raw_parts(ptr, length)
899                .iter()
900                .map(|ptr| CStr::from_ptr(*ptr).to_string_lossy().into_owned())
901                .collect();
902            ffi::rocksdb_list_column_families_destroy(ptr, length);
903            Ok(vec)
904        }
905    }
906
907    pub fn destroy<P: AsRef<Path>>(opts: &Options, path: P) -> Result<(), Error> {
908        let cpath = to_cpath(path)?;
909        unsafe {
910            ffi_try!(ffi::rocksdb_destroy_db(opts.inner, cpath.as_ptr()));
911        }
912        Ok(())
913    }
914
915    pub fn repair<P: AsRef<Path>>(opts: &Options, path: P) -> Result<(), Error> {
916        let cpath = to_cpath(path)?;
917        unsafe {
918            ffi_try!(ffi::rocksdb_repair_db(opts.inner, cpath.as_ptr()));
919        }
920        Ok(())
921    }
922
923    pub fn path(&self) -> &Path {
924        self.path.as_path()
925    }
926
927    /// Flushes the WAL buffer. If `sync` is set to `true`, also syncs
928    /// the data to disk.
929    pub fn flush_wal(&self, sync: bool) -> Result<(), Error> {
930        unsafe {
931            ffi_try!(ffi::rocksdb_flush_wal(
932                self.inner.inner(),
933                c_uchar::from(sync)
934            ));
935        }
936        Ok(())
937    }
938
939    /// Flushes database memtables to SST files on the disk.
940    pub fn flush_opt(&self, flushopts: &FlushOptions) -> Result<(), Error> {
941        unsafe {
942            ffi_try!(ffi::rocksdb_flush(self.inner.inner(), flushopts.inner));
943        }
944        Ok(())
945    }
946
947    /// Flushes database memtables to SST files on the disk using default options.
948    pub fn flush(&self) -> Result<(), Error> {
949        self.flush_opt(&FlushOptions::default())
950    }
951
952    /// Flushes database memtables to SST files on the disk for a given column family.
953    pub fn flush_cf_opt(
954        &self,
955        cf: &impl AsColumnFamilyRef,
956        flushopts: &FlushOptions,
957    ) -> Result<(), Error> {
958        unsafe {
959            ffi_try!(ffi::rocksdb_flush_cf(
960                self.inner.inner(),
961                flushopts.inner,
962                cf.inner()
963            ));
964        }
965        Ok(())
966    }
967
968    /// Flushes multiple column families.
969    ///
970    /// If atomic flush is not enabled, it is equivalent to calling flush_cf multiple times.
971    /// If atomic flush is enabled, it will flush all column families specified in `cfs` up to the latest sequence
972    /// number at the time when flush is requested.
973    pub fn flush_cfs_opt(
974        &self,
975        cfs: &[&impl AsColumnFamilyRef],
976        opts: &FlushOptions,
977    ) -> Result<(), Error> {
978        let mut cfs = cfs.iter().map(|cf| cf.inner()).collect::<Vec<_>>();
979        unsafe {
980            ffi_try!(ffi::rocksdb_flush_cfs(
981                self.inner.inner(),
982                opts.inner,
983                cfs.as_mut_ptr(),
984                cfs.len() as libc::c_int,
985            ));
986        }
987        Ok(())
988    }
989
990    /// Flushes database memtables to SST files on the disk for a given column family using default
991    /// options.
992    pub fn flush_cf(&self, cf: &impl AsColumnFamilyRef) -> Result<(), Error> {
993        self.flush_cf_opt(cf, &FlushOptions::default())
994    }
995
996    /// Return the bytes associated with a key value with read options. If you only intend to use
997    /// the vector returned temporarily, consider using [`get_pinned_opt`](#method.get_pinned_opt)
998    /// to avoid unnecessary memory copy.
999    pub fn get_opt<K: AsRef<[u8]>>(
1000        &self,
1001        key: K,
1002        readopts: &ReadOptions,
1003    ) -> Result<Option<Vec<u8>>, Error> {
1004        self.get_pinned_opt(key, readopts)
1005            .map(|x| x.map(|v| v.as_ref().to_vec()))
1006    }
1007
1008    /// Return the bytes associated with a key value. If you only intend to use the vector returned
1009    /// temporarily, consider using [`get_pinned`](#method.get_pinned) to avoid unnecessary memory
1010    /// copy.
1011    pub fn get<K: AsRef<[u8]>>(&self, key: K) -> Result<Option<Vec<u8>>, Error> {
1012        self.get_opt(key.as_ref(), &ReadOptions::default())
1013    }
1014
1015    /// Return the bytes associated with a key value and the given column family with read options.
1016    /// If you only intend to use the vector returned temporarily, consider using
1017    /// [`get_pinned_cf_opt`](#method.get_pinned_cf_opt) to avoid unnecessary memory.
1018    pub fn get_cf_opt<K: AsRef<[u8]>>(
1019        &self,
1020        cf: &impl AsColumnFamilyRef,
1021        key: K,
1022        readopts: &ReadOptions,
1023    ) -> Result<Option<Vec<u8>>, Error> {
1024        self.get_pinned_cf_opt(cf, key, readopts)
1025            .map(|x| x.map(|v| v.as_ref().to_vec()))
1026    }
1027
1028    /// Return the bytes associated with a key value and the given column family. If you only
1029    /// intend to use the vector returned temporarily, consider using
1030    /// [`get_pinned_cf`](#method.get_pinned_cf) to avoid unnecessary memory.
1031    pub fn get_cf<K: AsRef<[u8]>>(
1032        &self,
1033        cf: &impl AsColumnFamilyRef,
1034        key: K,
1035    ) -> Result<Option<Vec<u8>>, Error> {
1036        self.get_cf_opt(cf, key.as_ref(), &ReadOptions::default())
1037    }
1038
1039    /// Return the value associated with a key using RocksDB's PinnableSlice
1040    /// so as to avoid unnecessary memory copy.
1041    pub fn get_pinned_opt<K: AsRef<[u8]>>(
1042        &self,
1043        key: K,
1044        readopts: &ReadOptions,
1045    ) -> Result<Option<DBPinnableSlice>, Error> {
1046        if readopts.inner.is_null() {
1047            return Err(Error::new(
1048                "Unable to create RocksDB read options. This is a fairly trivial call, and its \
1049                 failure may be indicative of a mis-compiled or mis-loaded RocksDB library."
1050                    .to_owned(),
1051            ));
1052        }
1053
1054        let key = key.as_ref();
1055        unsafe {
1056            let val = ffi_try!(ffi::rocksdb_get_pinned(
1057                self.inner.inner(),
1058                readopts.inner,
1059                key.as_ptr() as *const c_char,
1060                key.len() as size_t,
1061            ));
1062            if val.is_null() {
1063                Ok(None)
1064            } else {
1065                Ok(Some(DBPinnableSlice::from_c(val)))
1066            }
1067        }
1068    }
1069
1070    /// Return the value associated with a key using RocksDB's PinnableSlice
1071    /// so as to avoid unnecessary memory copy. Similar to get_pinned_opt but
1072    /// leverages default options.
1073    pub fn get_pinned<K: AsRef<[u8]>>(&self, key: K) -> Result<Option<DBPinnableSlice>, Error> {
1074        self.get_pinned_opt(key, &ReadOptions::default())
1075    }
1076
1077    /// Return the value associated with a key using RocksDB's PinnableSlice
1078    /// so as to avoid unnecessary memory copy. Similar to get_pinned_opt but
1079    /// allows specifying ColumnFamily
1080    pub fn get_pinned_cf_opt<K: AsRef<[u8]>>(
1081        &self,
1082        cf: &impl AsColumnFamilyRef,
1083        key: K,
1084        readopts: &ReadOptions,
1085    ) -> Result<Option<DBPinnableSlice>, Error> {
1086        if readopts.inner.is_null() {
1087            return Err(Error::new(
1088                "Unable to create RocksDB read options. This is a fairly trivial call, and its \
1089                 failure may be indicative of a mis-compiled or mis-loaded RocksDB library."
1090                    .to_owned(),
1091            ));
1092        }
1093
1094        let key = key.as_ref();
1095        unsafe {
1096            let val = ffi_try!(ffi::rocksdb_get_pinned_cf(
1097                self.inner.inner(),
1098                readopts.inner,
1099                cf.inner(),
1100                key.as_ptr() as *const c_char,
1101                key.len() as size_t,
1102            ));
1103            if val.is_null() {
1104                Ok(None)
1105            } else {
1106                Ok(Some(DBPinnableSlice::from_c(val)))
1107            }
1108        }
1109    }
1110
1111    /// Return the value associated with a key using RocksDB's PinnableSlice
1112    /// so as to avoid unnecessary memory copy. Similar to get_pinned_cf_opt but
1113    /// leverages default options.
1114    pub fn get_pinned_cf<K: AsRef<[u8]>>(
1115        &self,
1116        cf: &impl AsColumnFamilyRef,
1117        key: K,
1118    ) -> Result<Option<DBPinnableSlice>, Error> {
1119        self.get_pinned_cf_opt(cf, key, &ReadOptions::default())
1120    }
1121
1122    /// Return the values associated with the given keys.
1123    pub fn multi_get<K, I>(&self, keys: I) -> Vec<Result<Option<Vec<u8>>, Error>>
1124    where
1125        K: AsRef<[u8]>,
1126        I: IntoIterator<Item = K>,
1127    {
1128        self.multi_get_opt(keys, &ReadOptions::default())
1129    }
1130
1131    /// Return the values associated with the given keys using read options.
1132    pub fn multi_get_opt<K, I>(
1133        &self,
1134        keys: I,
1135        readopts: &ReadOptions,
1136    ) -> Vec<Result<Option<Vec<u8>>, Error>>
1137    where
1138        K: AsRef<[u8]>,
1139        I: IntoIterator<Item = K>,
1140    {
1141        let (keys, keys_sizes): (Vec<Box<[u8]>>, Vec<_>) = keys
1142            .into_iter()
1143            .map(|k| {
1144                let k = k.as_ref();
1145                (Box::from(k), k.len())
1146            })
1147            .unzip();
1148        let ptr_keys: Vec<_> = keys.iter().map(|k| k.as_ptr() as *const c_char).collect();
1149
1150        let mut values = vec![ptr::null_mut(); keys.len()];
1151        let mut values_sizes = vec![0_usize; keys.len()];
1152        let mut errors = vec![ptr::null_mut(); keys.len()];
1153        unsafe {
1154            ffi::rocksdb_multi_get(
1155                self.inner.inner(),
1156                readopts.inner,
1157                ptr_keys.len(),
1158                ptr_keys.as_ptr(),
1159                keys_sizes.as_ptr(),
1160                values.as_mut_ptr(),
1161                values_sizes.as_mut_ptr(),
1162                errors.as_mut_ptr(),
1163            );
1164        }
1165
1166        convert_values(values, values_sizes, errors)
1167    }
1168
1169    /// Return the values associated with the given keys and column families.
1170    pub fn multi_get_cf<'a, 'b: 'a, K, I, W>(
1171        &'a self,
1172        keys: I,
1173    ) -> Vec<Result<Option<Vec<u8>>, Error>>
1174    where
1175        K: AsRef<[u8]>,
1176        I: IntoIterator<Item = (&'b W, K)>,
1177        W: 'b + AsColumnFamilyRef,
1178    {
1179        self.multi_get_cf_opt(keys, &ReadOptions::default())
1180    }
1181
1182    /// Return the values associated with the given keys and column families using read options.
1183    pub fn multi_get_cf_opt<'a, 'b: 'a, K, I, W>(
1184        &'a self,
1185        keys: I,
1186        readopts: &ReadOptions,
1187    ) -> Vec<Result<Option<Vec<u8>>, Error>>
1188    where
1189        K: AsRef<[u8]>,
1190        I: IntoIterator<Item = (&'b W, K)>,
1191        W: 'b + AsColumnFamilyRef,
1192    {
1193        let (cfs_and_keys, keys_sizes): (Vec<(_, Box<[u8]>)>, Vec<_>) = keys
1194            .into_iter()
1195            .map(|(cf, key)| {
1196                let key = key.as_ref();
1197                ((cf, Box::from(key)), key.len())
1198            })
1199            .unzip();
1200        let ptr_keys: Vec<_> = cfs_and_keys
1201            .iter()
1202            .map(|(_, k)| k.as_ptr() as *const c_char)
1203            .collect();
1204        let ptr_cfs: Vec<_> = cfs_and_keys
1205            .iter()
1206            .map(|(c, _)| c.inner().cast_const())
1207            .collect();
1208
1209        let mut values = vec![ptr::null_mut(); ptr_keys.len()];
1210        let mut values_sizes = vec![0_usize; ptr_keys.len()];
1211        let mut errors = vec![ptr::null_mut(); ptr_keys.len()];
1212        unsafe {
1213            ffi::rocksdb_multi_get_cf(
1214                self.inner.inner(),
1215                readopts.inner,
1216                ptr_cfs.as_ptr(),
1217                ptr_keys.len(),
1218                ptr_keys.as_ptr(),
1219                keys_sizes.as_ptr(),
1220                values.as_mut_ptr(),
1221                values_sizes.as_mut_ptr(),
1222                errors.as_mut_ptr(),
1223            );
1224        }
1225
1226        convert_values(values, values_sizes, errors)
1227    }
1228
1229    /// Return the values associated with the given keys and the specified column family
1230    /// where internally the read requests are processed in batch if block-based table
1231    /// SST format is used.  It is a more optimized version of multi_get_cf.
1232    pub fn batched_multi_get_cf<'a, K, I>(
1233        &self,
1234        cf: &impl AsColumnFamilyRef,
1235        keys: I,
1236        sorted_input: bool,
1237    ) -> Vec<Result<Option<DBPinnableSlice>, Error>>
1238    where
1239        K: AsRef<[u8]> + 'a + ?Sized,
1240        I: IntoIterator<Item = &'a K>,
1241    {
1242        self.batched_multi_get_cf_opt(cf, keys, sorted_input, &ReadOptions::default())
1243    }
1244
1245    /// Return the values associated with the given keys and the specified column family
1246    /// where internally the read requests are processed in batch if block-based table
1247    /// SST format is used. It is a more optimized version of multi_get_cf_opt.
1248    pub fn batched_multi_get_cf_opt<'a, K, I>(
1249        &self,
1250        cf: &impl AsColumnFamilyRef,
1251        keys: I,
1252        sorted_input: bool,
1253        readopts: &ReadOptions,
1254    ) -> Vec<Result<Option<DBPinnableSlice>, Error>>
1255    where
1256        K: AsRef<[u8]> + 'a + ?Sized,
1257        I: IntoIterator<Item = &'a K>,
1258    {
1259        let (ptr_keys, keys_sizes): (Vec<_>, Vec<_>) = keys
1260            .into_iter()
1261            .map(|k| {
1262                let k = k.as_ref();
1263                (k.as_ptr() as *const c_char, k.len())
1264            })
1265            .unzip();
1266
1267        let mut pinned_values = vec![ptr::null_mut(); ptr_keys.len()];
1268        let mut errors = vec![ptr::null_mut(); ptr_keys.len()];
1269
1270        unsafe {
1271            ffi::rocksdb_batched_multi_get_cf(
1272                self.inner.inner(),
1273                readopts.inner,
1274                cf.inner(),
1275                ptr_keys.len(),
1276                ptr_keys.as_ptr(),
1277                keys_sizes.as_ptr(),
1278                pinned_values.as_mut_ptr(),
1279                errors.as_mut_ptr(),
1280                sorted_input,
1281            );
1282            pinned_values
1283                .into_iter()
1284                .zip(errors)
1285                .map(|(v, e)| {
1286                    if e.is_null() {
1287                        if v.is_null() {
1288                            Ok(None)
1289                        } else {
1290                            Ok(Some(DBPinnableSlice::from_c(v)))
1291                        }
1292                    } else {
1293                        Err(Error::new(crate::ffi_util::error_message(e)))
1294                    }
1295                })
1296                .collect()
1297        }
1298    }
1299
1300    /// Returns `false` if the given key definitely doesn't exist in the database, otherwise returns
1301    /// `true`. This function uses default `ReadOptions`.
1302    pub fn key_may_exist<K: AsRef<[u8]>>(&self, key: K) -> bool {
1303        self.key_may_exist_opt(key, &ReadOptions::default())
1304    }
1305
1306    /// Returns `false` if the given key definitely doesn't exist in the database, otherwise returns
1307    /// `true`.
1308    pub fn key_may_exist_opt<K: AsRef<[u8]>>(&self, key: K, readopts: &ReadOptions) -> bool {
1309        let key = key.as_ref();
1310        unsafe {
1311            0 != ffi::rocksdb_key_may_exist(
1312                self.inner.inner(),
1313                readopts.inner,
1314                key.as_ptr() as *const c_char,
1315                key.len() as size_t,
1316                ptr::null_mut(), /*value*/
1317                ptr::null_mut(), /*val_len*/
1318                ptr::null(),     /*timestamp*/
1319                0,               /*timestamp_len*/
1320                ptr::null_mut(), /*value_found*/
1321            )
1322        }
1323    }
1324
1325    /// Returns `false` if the given key definitely doesn't exist in the specified column family,
1326    /// otherwise returns `true`. This function uses default `ReadOptions`.
1327    pub fn key_may_exist_cf<K: AsRef<[u8]>>(&self, cf: &impl AsColumnFamilyRef, key: K) -> bool {
1328        self.key_may_exist_cf_opt(cf, key, &ReadOptions::default())
1329    }
1330
1331    /// Returns `false` if the given key definitely doesn't exist in the specified column family,
1332    /// otherwise returns `true`.
1333    pub fn key_may_exist_cf_opt<K: AsRef<[u8]>>(
1334        &self,
1335        cf: &impl AsColumnFamilyRef,
1336        key: K,
1337        readopts: &ReadOptions,
1338    ) -> bool {
1339        let key = key.as_ref();
1340        0 != unsafe {
1341            ffi::rocksdb_key_may_exist_cf(
1342                self.inner.inner(),
1343                readopts.inner,
1344                cf.inner(),
1345                key.as_ptr() as *const c_char,
1346                key.len() as size_t,
1347                ptr::null_mut(), /*value*/
1348                ptr::null_mut(), /*val_len*/
1349                ptr::null(),     /*timestamp*/
1350                0,               /*timestamp_len*/
1351                ptr::null_mut(), /*value_found*/
1352            )
1353        }
1354    }
1355
1356    /// If the key definitely does not exist in the database, then this method
1357    /// returns `(false, None)`, else `(true, None)` if it may.
1358    /// If the key is found in memory, then it returns `(true, Some<CSlice>)`.
1359    ///
1360    /// This check is potentially lighter-weight than calling `get()`. One way
1361    /// to make this lighter weight is to avoid doing any IOs.
1362    pub fn key_may_exist_cf_opt_value<K: AsRef<[u8]>>(
1363        &self,
1364        cf: &impl AsColumnFamilyRef,
1365        key: K,
1366        readopts: &ReadOptions,
1367    ) -> (bool, Option<CSlice>) {
1368        let key = key.as_ref();
1369        let mut val: *mut c_char = ptr::null_mut();
1370        let mut val_len: usize = 0;
1371        let mut value_found: c_uchar = 0;
1372        let may_exists = 0
1373            != unsafe {
1374                ffi::rocksdb_key_may_exist_cf(
1375                    self.inner.inner(),
1376                    readopts.inner,
1377                    cf.inner(),
1378                    key.as_ptr() as *const c_char,
1379                    key.len() as size_t,
1380                    &mut val,         /*value*/
1381                    &mut val_len,     /*val_len*/
1382                    ptr::null(),      /*timestamp*/
1383                    0,                /*timestamp_len*/
1384                    &mut value_found, /*value_found*/
1385                )
1386            };
1387        // The value is only allocated (using malloc) and returned if it is found and
1388        // value_found isn't NULL. In that case the user is responsible for freeing it.
1389        if may_exists && value_found != 0 {
1390            (
1391                may_exists,
1392                Some(unsafe { CSlice::from_raw_parts(val, val_len) }),
1393            )
1394        } else {
1395            (may_exists, None)
1396        }
1397    }
1398
1399    fn create_inner_cf_handle(
1400        &self,
1401        name: impl CStrLike,
1402        opts: &Options,
1403    ) -> Result<*mut ffi::rocksdb_column_family_handle_t, Error> {
1404        let cf_name = name.bake().map_err(|err| {
1405            Error::new(format!(
1406                "Failed to convert path to CString when creating cf: {err}"
1407            ))
1408        })?;
1409        Ok(unsafe {
1410            ffi_try!(ffi::rocksdb_create_column_family(
1411                self.inner.inner(),
1412                opts.inner,
1413                cf_name.as_ptr(),
1414            ))
1415        })
1416    }
1417
1418    pub fn iterator<'a: 'b, 'b>(
1419        &'a self,
1420        mode: IteratorMode,
1421    ) -> DBIteratorWithThreadMode<'b, Self> {
1422        let readopts = ReadOptions::default();
1423        self.iterator_opt(mode, readopts)
1424    }
1425
1426    pub fn iterator_opt<'a: 'b, 'b>(
1427        &'a self,
1428        mode: IteratorMode,
1429        readopts: ReadOptions,
1430    ) -> DBIteratorWithThreadMode<'b, Self> {
1431        DBIteratorWithThreadMode::new(self, readopts, mode)
1432    }
1433
1434    /// Opens an iterator using the provided ReadOptions.
1435    /// This is used when you want to iterate over a specific ColumnFamily with a modified ReadOptions
1436    pub fn iterator_cf_opt<'a: 'b, 'b>(
1437        &'a self,
1438        cf_handle: &impl AsColumnFamilyRef,
1439        readopts: ReadOptions,
1440        mode: IteratorMode,
1441    ) -> DBIteratorWithThreadMode<'b, Self> {
1442        DBIteratorWithThreadMode::new_cf(self, cf_handle.inner(), readopts, mode)
1443    }
1444
1445    /// Opens an iterator with `set_total_order_seek` enabled.
1446    /// This must be used to iterate across prefixes when `set_memtable_factory` has been called
1447    /// with a Hash-based implementation.
1448    pub fn full_iterator<'a: 'b, 'b>(
1449        &'a self,
1450        mode: IteratorMode,
1451    ) -> DBIteratorWithThreadMode<'b, Self> {
1452        let mut opts = ReadOptions::default();
1453        opts.set_total_order_seek(true);
1454        DBIteratorWithThreadMode::new(self, opts, mode)
1455    }
1456
1457    pub fn prefix_iterator<'a: 'b, 'b, P: AsRef<[u8]>>(
1458        &'a self,
1459        prefix: P,
1460    ) -> DBIteratorWithThreadMode<'b, Self> {
1461        let mut opts = ReadOptions::default();
1462        opts.set_prefix_same_as_start(true);
1463        DBIteratorWithThreadMode::new(
1464            self,
1465            opts,
1466            IteratorMode::From(prefix.as_ref(), Direction::Forward),
1467        )
1468    }
1469
1470    pub fn iterator_cf<'a: 'b, 'b>(
1471        &'a self,
1472        cf_handle: &impl AsColumnFamilyRef,
1473        mode: IteratorMode,
1474    ) -> DBIteratorWithThreadMode<'b, Self> {
1475        let opts = ReadOptions::default();
1476        DBIteratorWithThreadMode::new_cf(self, cf_handle.inner(), opts, mode)
1477    }
1478
1479    pub fn full_iterator_cf<'a: 'b, 'b>(
1480        &'a self,
1481        cf_handle: &impl AsColumnFamilyRef,
1482        mode: IteratorMode,
1483    ) -> DBIteratorWithThreadMode<'b, Self> {
1484        let mut opts = ReadOptions::default();
1485        opts.set_total_order_seek(true);
1486        DBIteratorWithThreadMode::new_cf(self, cf_handle.inner(), opts, mode)
1487    }
1488
1489    pub fn prefix_iterator_cf<'a, P: AsRef<[u8]>>(
1490        &'a self,
1491        cf_handle: &impl AsColumnFamilyRef,
1492        prefix: P,
1493    ) -> DBIteratorWithThreadMode<'a, Self> {
1494        let mut opts = ReadOptions::default();
1495        opts.set_prefix_same_as_start(true);
1496        DBIteratorWithThreadMode::<'a, Self>::new_cf(
1497            self,
1498            cf_handle.inner(),
1499            opts,
1500            IteratorMode::From(prefix.as_ref(), Direction::Forward),
1501        )
1502    }
1503
1504    /// Opens a raw iterator over the database, using the default read options
1505    pub fn raw_iterator<'a: 'b, 'b>(&'a self) -> DBRawIteratorWithThreadMode<'b, Self> {
1506        let opts = ReadOptions::default();
1507        DBRawIteratorWithThreadMode::new(self, opts)
1508    }
1509
1510    /// Opens a raw iterator over the given column family, using the default read options
1511    pub fn raw_iterator_cf<'a: 'b, 'b>(
1512        &'a self,
1513        cf_handle: &impl AsColumnFamilyRef,
1514    ) -> DBRawIteratorWithThreadMode<'b, Self> {
1515        let opts = ReadOptions::default();
1516        DBRawIteratorWithThreadMode::new_cf(self, cf_handle.inner(), opts)
1517    }
1518
1519    /// Opens a raw iterator over the database, using the given read options
1520    pub fn raw_iterator_opt<'a: 'b, 'b>(
1521        &'a self,
1522        readopts: ReadOptions,
1523    ) -> DBRawIteratorWithThreadMode<'b, Self> {
1524        DBRawIteratorWithThreadMode::new(self, readopts)
1525    }
1526
1527    /// Opens a raw iterator over the given column family, using the given read options
1528    pub fn raw_iterator_cf_opt<'a: 'b, 'b>(
1529        &'a self,
1530        cf_handle: &impl AsColumnFamilyRef,
1531        readopts: ReadOptions,
1532    ) -> DBRawIteratorWithThreadMode<'b, Self> {
1533        DBRawIteratorWithThreadMode::new_cf(self, cf_handle.inner(), readopts)
1534    }
1535
1536    pub fn snapshot(&self) -> SnapshotWithThreadMode<Self> {
1537        SnapshotWithThreadMode::<Self>::new(self)
1538    }
1539
1540    pub fn put_opt<K, V>(&self, key: K, value: V, writeopts: &WriteOptions) -> Result<(), Error>
1541    where
1542        K: AsRef<[u8]>,
1543        V: AsRef<[u8]>,
1544    {
1545        let key = key.as_ref();
1546        let value = value.as_ref();
1547
1548        unsafe {
1549            ffi_try!(ffi::rocksdb_put(
1550                self.inner.inner(),
1551                writeopts.inner,
1552                key.as_ptr() as *const c_char,
1553                key.len() as size_t,
1554                value.as_ptr() as *const c_char,
1555                value.len() as size_t,
1556            ));
1557            Ok(())
1558        }
1559    }
1560
1561    pub fn put_cf_opt<K, V>(
1562        &self,
1563        cf: &impl AsColumnFamilyRef,
1564        key: K,
1565        value: V,
1566        writeopts: &WriteOptions,
1567    ) -> Result<(), Error>
1568    where
1569        K: AsRef<[u8]>,
1570        V: AsRef<[u8]>,
1571    {
1572        let key = key.as_ref();
1573        let value = value.as_ref();
1574
1575        unsafe {
1576            ffi_try!(ffi::rocksdb_put_cf(
1577                self.inner.inner(),
1578                writeopts.inner,
1579                cf.inner(),
1580                key.as_ptr() as *const c_char,
1581                key.len() as size_t,
1582                value.as_ptr() as *const c_char,
1583                value.len() as size_t,
1584            ));
1585            Ok(())
1586        }
1587    }
1588
1589    /// Set the database entry for "key" to "value" with WriteOptions.
1590    /// If "key" already exists, it will coexist with previous entry.
1591    /// `Get` with a timestamp ts specified in ReadOptions will return
1592    /// the most recent key/value whose timestamp is smaller than or equal to ts.
1593    /// Takes an additional argument `ts` as the timestamp.
1594    /// Note: the DB must be opened with user defined timestamp enabled.
1595    pub fn put_with_ts_opt<K, V, S>(
1596        &self,
1597        key: K,
1598        ts: S,
1599        value: V,
1600        writeopts: &WriteOptions,
1601    ) -> Result<(), Error>
1602    where
1603        K: AsRef<[u8]>,
1604        V: AsRef<[u8]>,
1605        S: AsRef<[u8]>,
1606    {
1607        let key = key.as_ref();
1608        let value = value.as_ref();
1609        let ts = ts.as_ref();
1610        unsafe {
1611            ffi_try!(ffi::rocksdb_put_with_ts(
1612                self.inner.inner(),
1613                writeopts.inner,
1614                key.as_ptr() as *const c_char,
1615                key.len() as size_t,
1616                ts.as_ptr() as *const c_char,
1617                ts.len() as size_t,
1618                value.as_ptr() as *const c_char,
1619                value.len() as size_t,
1620            ));
1621            Ok(())
1622        }
1623    }
1624
1625    /// Put with timestamp in a specific column family with WriteOptions.
1626    /// If "key" already exists, it will coexist with previous entry.
1627    /// `Get` with a timestamp ts specified in ReadOptions will return
1628    /// the most recent key/value whose timestamp is smaller than or equal to ts.
1629    /// Takes an additional argument `ts` as the timestamp.
1630    /// Note: the DB must be opened with user defined timestamp enabled.
1631    pub fn put_cf_with_ts_opt<K, V, S>(
1632        &self,
1633        cf: &impl AsColumnFamilyRef,
1634        key: K,
1635        ts: S,
1636        value: V,
1637        writeopts: &WriteOptions,
1638    ) -> Result<(), Error>
1639    where
1640        K: AsRef<[u8]>,
1641        V: AsRef<[u8]>,
1642        S: AsRef<[u8]>,
1643    {
1644        let key = key.as_ref();
1645        let value = value.as_ref();
1646        let ts = ts.as_ref();
1647        unsafe {
1648            ffi_try!(ffi::rocksdb_put_cf_with_ts(
1649                self.inner.inner(),
1650                writeopts.inner,
1651                cf.inner(),
1652                key.as_ptr() as *const c_char,
1653                key.len() as size_t,
1654                ts.as_ptr() as *const c_char,
1655                ts.len() as size_t,
1656                value.as_ptr() as *const c_char,
1657                value.len() as size_t,
1658            ));
1659            Ok(())
1660        }
1661    }
1662
1663    pub fn merge_opt<K, V>(&self, key: K, value: V, writeopts: &WriteOptions) -> Result<(), Error>
1664    where
1665        K: AsRef<[u8]>,
1666        V: AsRef<[u8]>,
1667    {
1668        let key = key.as_ref();
1669        let value = value.as_ref();
1670
1671        unsafe {
1672            ffi_try!(ffi::rocksdb_merge(
1673                self.inner.inner(),
1674                writeopts.inner,
1675                key.as_ptr() as *const c_char,
1676                key.len() as size_t,
1677                value.as_ptr() as *const c_char,
1678                value.len() as size_t,
1679            ));
1680            Ok(())
1681        }
1682    }
1683
1684    pub fn merge_cf_opt<K, V>(
1685        &self,
1686        cf: &impl AsColumnFamilyRef,
1687        key: K,
1688        value: V,
1689        writeopts: &WriteOptions,
1690    ) -> Result<(), Error>
1691    where
1692        K: AsRef<[u8]>,
1693        V: AsRef<[u8]>,
1694    {
1695        let key = key.as_ref();
1696        let value = value.as_ref();
1697
1698        unsafe {
1699            ffi_try!(ffi::rocksdb_merge_cf(
1700                self.inner.inner(),
1701                writeopts.inner,
1702                cf.inner(),
1703                key.as_ptr() as *const c_char,
1704                key.len() as size_t,
1705                value.as_ptr() as *const c_char,
1706                value.len() as size_t,
1707            ));
1708            Ok(())
1709        }
1710    }
1711
1712    pub fn delete_opt<K: AsRef<[u8]>>(
1713        &self,
1714        key: K,
1715        writeopts: &WriteOptions,
1716    ) -> Result<(), Error> {
1717        let key = key.as_ref();
1718
1719        unsafe {
1720            ffi_try!(ffi::rocksdb_delete(
1721                self.inner.inner(),
1722                writeopts.inner,
1723                key.as_ptr() as *const c_char,
1724                key.len() as size_t,
1725            ));
1726            Ok(())
1727        }
1728    }
1729
1730    pub fn delete_cf_opt<K: AsRef<[u8]>>(
1731        &self,
1732        cf: &impl AsColumnFamilyRef,
1733        key: K,
1734        writeopts: &WriteOptions,
1735    ) -> Result<(), Error> {
1736        let key = key.as_ref();
1737
1738        unsafe {
1739            ffi_try!(ffi::rocksdb_delete_cf(
1740                self.inner.inner(),
1741                writeopts.inner,
1742                cf.inner(),
1743                key.as_ptr() as *const c_char,
1744                key.len() as size_t,
1745            ));
1746            Ok(())
1747        }
1748    }
1749
1750    /// Remove the database entry (if any) for "key" with WriteOptions.
1751    /// Takes an additional argument `ts` as the timestamp.
1752    /// Note: the DB must be opened with user defined timestamp enabled.
1753    pub fn delete_with_ts_opt<K, S>(
1754        &self,
1755        key: K,
1756        ts: S,
1757        writeopts: &WriteOptions,
1758    ) -> Result<(), Error>
1759    where
1760        K: AsRef<[u8]>,
1761        S: AsRef<[u8]>,
1762    {
1763        let key = key.as_ref();
1764        let ts = ts.as_ref();
1765        unsafe {
1766            ffi_try!(ffi::rocksdb_delete_with_ts(
1767                self.inner.inner(),
1768                writeopts.inner,
1769                key.as_ptr() as *const c_char,
1770                key.len() as size_t,
1771                ts.as_ptr() as *const c_char,
1772                ts.len() as size_t,
1773            ));
1774            Ok(())
1775        }
1776    }
1777
1778    /// Delete with timestamp in a specific column family with WriteOptions.
1779    /// Takes an additional argument `ts` as the timestamp.
1780    /// Note: the DB must be opened with user defined timestamp enabled.
1781    pub fn delete_cf_with_ts_opt<K, S>(
1782        &self,
1783        cf: &impl AsColumnFamilyRef,
1784        key: K,
1785        ts: S,
1786        writeopts: &WriteOptions,
1787    ) -> Result<(), Error>
1788    where
1789        K: AsRef<[u8]>,
1790        S: AsRef<[u8]>,
1791    {
1792        let key = key.as_ref();
1793        let ts = ts.as_ref();
1794        unsafe {
1795            ffi_try!(ffi::rocksdb_delete_cf_with_ts(
1796                self.inner.inner(),
1797                writeopts.inner,
1798                cf.inner(),
1799                key.as_ptr() as *const c_char,
1800                key.len() as size_t,
1801                ts.as_ptr() as *const c_char,
1802                ts.len() as size_t,
1803            ));
1804            Ok(())
1805        }
1806    }
1807
1808    pub fn put<K, V>(&self, key: K, value: V) -> Result<(), Error>
1809    where
1810        K: AsRef<[u8]>,
1811        V: AsRef<[u8]>,
1812    {
1813        self.put_opt(key.as_ref(), value.as_ref(), &WriteOptions::default())
1814    }
1815
1816    pub fn put_cf<K, V>(&self, cf: &impl AsColumnFamilyRef, key: K, value: V) -> Result<(), Error>
1817    where
1818        K: AsRef<[u8]>,
1819        V: AsRef<[u8]>,
1820    {
1821        self.put_cf_opt(cf, key.as_ref(), value.as_ref(), &WriteOptions::default())
1822    }
1823
1824    /// Set the database entry for "key" to "value".
1825    /// If "key" already exists, it will coexist with previous entry.
1826    /// `Get` with a timestamp ts specified in ReadOptions will return
1827    /// the most recent key/value whose timestamp is smaller than or equal to ts.
1828    /// Takes an additional argument `ts` as the timestamp.
1829    /// Note: the DB must be opened with user defined timestamp enabled.
1830    pub fn put_with_ts<K, V, S>(&self, key: K, ts: S, value: V) -> Result<(), Error>
1831    where
1832        K: AsRef<[u8]>,
1833        V: AsRef<[u8]>,
1834        S: AsRef<[u8]>,
1835    {
1836        self.put_with_ts_opt(
1837            key.as_ref(),
1838            ts.as_ref(),
1839            value.as_ref(),
1840            &WriteOptions::default(),
1841        )
1842    }
1843
1844    /// Put with timestamp in a specific column family.
1845    /// If "key" already exists, it will coexist with previous entry.
1846    /// `Get` with a timestamp ts specified in ReadOptions will return
1847    /// the most recent key/value whose timestamp is smaller than or equal to ts.
1848    /// Takes an additional argument `ts` as the timestamp.
1849    /// Note: the DB must be opened with user defined timestamp enabled.
1850    pub fn put_cf_with_ts<K, V, S>(
1851        &self,
1852        cf: &impl AsColumnFamilyRef,
1853        key: K,
1854        ts: S,
1855        value: V,
1856    ) -> Result<(), Error>
1857    where
1858        K: AsRef<[u8]>,
1859        V: AsRef<[u8]>,
1860        S: AsRef<[u8]>,
1861    {
1862        self.put_cf_with_ts_opt(
1863            cf,
1864            key.as_ref(),
1865            ts.as_ref(),
1866            value.as_ref(),
1867            &WriteOptions::default(),
1868        )
1869    }
1870
1871    pub fn merge<K, V>(&self, key: K, value: V) -> Result<(), Error>
1872    where
1873        K: AsRef<[u8]>,
1874        V: AsRef<[u8]>,
1875    {
1876        self.merge_opt(key.as_ref(), value.as_ref(), &WriteOptions::default())
1877    }
1878
1879    pub fn merge_cf<K, V>(&self, cf: &impl AsColumnFamilyRef, key: K, value: V) -> Result<(), Error>
1880    where
1881        K: AsRef<[u8]>,
1882        V: AsRef<[u8]>,
1883    {
1884        self.merge_cf_opt(cf, key.as_ref(), value.as_ref(), &WriteOptions::default())
1885    }
1886
1887    pub fn delete<K: AsRef<[u8]>>(&self, key: K) -> Result<(), Error> {
1888        self.delete_opt(key.as_ref(), &WriteOptions::default())
1889    }
1890
1891    pub fn delete_cf<K: AsRef<[u8]>>(
1892        &self,
1893        cf: &impl AsColumnFamilyRef,
1894        key: K,
1895    ) -> Result<(), Error> {
1896        self.delete_cf_opt(cf, key.as_ref(), &WriteOptions::default())
1897    }
1898
1899    /// Remove the database entry (if any) for "key".
1900    /// Takes an additional argument `ts` as the timestamp.
1901    /// Note: the DB must be opened with user defined timestamp enabled.
1902    pub fn delete_with_ts<K: AsRef<[u8]>, S: AsRef<[u8]>>(
1903        &self,
1904        key: K,
1905        ts: S,
1906    ) -> Result<(), Error> {
1907        self.delete_with_ts_opt(key.as_ref(), ts.as_ref(), &WriteOptions::default())
1908    }
1909
1910    /// Delete with timestamp in a specific column family.
1911    /// Takes an additional argument `ts` as the timestamp.
1912    /// Note: the DB must be opened with user defined timestamp enabled.
1913    pub fn delete_cf_with_ts<K: AsRef<[u8]>, S: AsRef<[u8]>>(
1914        &self,
1915        cf: &impl AsColumnFamilyRef,
1916        key: K,
1917        ts: S,
1918    ) -> Result<(), Error> {
1919        self.delete_cf_with_ts_opt(cf, key.as_ref(), ts.as_ref(), &WriteOptions::default())
1920    }
1921
1922    /// Runs a manual compaction on the Range of keys given. This is not likely to be needed for typical usage.
1923    pub fn compact_range<S: AsRef<[u8]>, E: AsRef<[u8]>>(&self, start: Option<S>, end: Option<E>) {
1924        unsafe {
1925            let start = start.as_ref().map(AsRef::as_ref);
1926            let end = end.as_ref().map(AsRef::as_ref);
1927
1928            ffi::rocksdb_compact_range(
1929                self.inner.inner(),
1930                opt_bytes_to_ptr(start),
1931                start.map_or(0, <[u8]>::len) as size_t,
1932                opt_bytes_to_ptr(end),
1933                end.map_or(0, <[u8]>::len) as size_t,
1934            );
1935        }
1936    }
1937
1938    /// Same as `compact_range` but with custom options.
1939    pub fn compact_range_opt<S: AsRef<[u8]>, E: AsRef<[u8]>>(
1940        &self,
1941        start: Option<S>,
1942        end: Option<E>,
1943        opts: &CompactOptions,
1944    ) {
1945        unsafe {
1946            let start = start.as_ref().map(AsRef::as_ref);
1947            let end = end.as_ref().map(AsRef::as_ref);
1948
1949            ffi::rocksdb_compact_range_opt(
1950                self.inner.inner(),
1951                opts.inner,
1952                opt_bytes_to_ptr(start),
1953                start.map_or(0, <[u8]>::len) as size_t,
1954                opt_bytes_to_ptr(end),
1955                end.map_or(0, <[u8]>::len) as size_t,
1956            );
1957        }
1958    }
1959
1960    /// Runs a manual compaction on the Range of keys given on the
1961    /// given column family. This is not likely to be needed for typical usage.
1962    pub fn compact_range_cf<S: AsRef<[u8]>, E: AsRef<[u8]>>(
1963        &self,
1964        cf: &impl AsColumnFamilyRef,
1965        start: Option<S>,
1966        end: Option<E>,
1967    ) {
1968        unsafe {
1969            let start = start.as_ref().map(AsRef::as_ref);
1970            let end = end.as_ref().map(AsRef::as_ref);
1971
1972            ffi::rocksdb_compact_range_cf(
1973                self.inner.inner(),
1974                cf.inner(),
1975                opt_bytes_to_ptr(start),
1976                start.map_or(0, <[u8]>::len) as size_t,
1977                opt_bytes_to_ptr(end),
1978                end.map_or(0, <[u8]>::len) as size_t,
1979            );
1980        }
1981    }
1982
1983    /// Same as `compact_range_cf` but with custom options.
1984    pub fn compact_range_cf_opt<S: AsRef<[u8]>, E: AsRef<[u8]>>(
1985        &self,
1986        cf: &impl AsColumnFamilyRef,
1987        start: Option<S>,
1988        end: Option<E>,
1989        opts: &CompactOptions,
1990    ) {
1991        unsafe {
1992            let start = start.as_ref().map(AsRef::as_ref);
1993            let end = end.as_ref().map(AsRef::as_ref);
1994
1995            ffi::rocksdb_compact_range_cf_opt(
1996                self.inner.inner(),
1997                cf.inner(),
1998                opts.inner,
1999                opt_bytes_to_ptr(start),
2000                start.map_or(0, <[u8]>::len) as size_t,
2001                opt_bytes_to_ptr(end),
2002                end.map_or(0, <[u8]>::len) as size_t,
2003            );
2004        }
2005    }
2006
2007    /// Wait for all flush and compactions jobs to finish. Jobs to wait include the
2008    /// unscheduled (queued, but not scheduled yet).
2009    ///
2010    /// NOTE: This may also never return if there's sufficient ongoing writes that
2011    /// keeps flush and compaction going without stopping. The user would have to
2012    /// cease all the writes to DB to make this eventually return in a stable
2013    /// state. The user may also use timeout option in WaitForCompactOptions to
2014    /// make this stop waiting and return when timeout expires.
2015    pub fn wait_for_compact(&self, opts: &WaitForCompactOptions) -> Result<(), Error> {
2016        unsafe {
2017            ffi_try!(ffi::rocksdb_wait_for_compact(
2018                self.inner.inner(),
2019                opts.inner
2020            ));
2021        }
2022        Ok(())
2023    }
2024
2025    pub fn set_options(&self, opts: &[(&str, &str)]) -> Result<(), Error> {
2026        let copts = convert_options(opts)?;
2027        let cnames: Vec<*const c_char> = copts.iter().map(|opt| opt.0.as_ptr()).collect();
2028        let cvalues: Vec<*const c_char> = copts.iter().map(|opt| opt.1.as_ptr()).collect();
2029        let count = opts.len() as i32;
2030        unsafe {
2031            ffi_try!(ffi::rocksdb_set_options(
2032                self.inner.inner(),
2033                count,
2034                cnames.as_ptr(),
2035                cvalues.as_ptr(),
2036            ));
2037        }
2038        Ok(())
2039    }
2040
2041    pub fn set_options_cf(
2042        &self,
2043        cf: &impl AsColumnFamilyRef,
2044        opts: &[(&str, &str)],
2045    ) -> Result<(), Error> {
2046        let copts = convert_options(opts)?;
2047        let cnames: Vec<*const c_char> = copts.iter().map(|opt| opt.0.as_ptr()).collect();
2048        let cvalues: Vec<*const c_char> = copts.iter().map(|opt| opt.1.as_ptr()).collect();
2049        let count = opts.len() as i32;
2050        unsafe {
2051            ffi_try!(ffi::rocksdb_set_options_cf(
2052                self.inner.inner(),
2053                cf.inner(),
2054                count,
2055                cnames.as_ptr(),
2056                cvalues.as_ptr(),
2057            ));
2058        }
2059        Ok(())
2060    }
2061
2062    /// Implementation for property_value et al methods.
2063    ///
2064    /// `name` is the name of the property.  It will be converted into a CString
2065    /// and passed to `get_property` as argument.  `get_property` reads the
2066    /// specified property and either returns NULL or a pointer to a C allocated
2067    /// string; this method takes ownership of that string and will free it at
2068    /// the end. That string is parsed using `parse` callback which produces
2069    /// the returned result.
2070    fn property_value_impl<R>(
2071        name: impl CStrLike,
2072        get_property: impl FnOnce(*const c_char) -> *mut c_char,
2073        parse: impl FnOnce(&str) -> Result<R, Error>,
2074    ) -> Result<Option<R>, Error> {
2075        let value = match name.bake() {
2076            Ok(prop_name) => get_property(prop_name.as_ptr()),
2077            Err(e) => {
2078                return Err(Error::new(format!(
2079                    "Failed to convert property name to CString: {e}"
2080                )));
2081            }
2082        };
2083        if value.is_null() {
2084            return Ok(None);
2085        }
2086        let result = match unsafe { CStr::from_ptr(value) }.to_str() {
2087            Ok(s) => parse(s).map(|value| Some(value)),
2088            Err(e) => Err(Error::new(format!(
2089                "Failed to convert property value to string: {e}"
2090            ))),
2091        };
2092        unsafe {
2093            ffi::rocksdb_free(value as *mut c_void);
2094        }
2095        result
2096    }
2097
2098    /// Retrieves a RocksDB property by name.
2099    ///
2100    /// Full list of properties could be find
2101    /// [here](https://github.com/facebook/rocksdb/blob/08809f5e6cd9cc4bc3958dd4d59457ae78c76660/include/rocksdb/db.h#L428-L634).
2102    pub fn property_value(&self, name: impl CStrLike) -> Result<Option<String>, Error> {
2103        Self::property_value_impl(
2104            name,
2105            |prop_name| unsafe { ffi::rocksdb_property_value(self.inner.inner(), prop_name) },
2106            |str_value| Ok(str_value.to_owned()),
2107        )
2108    }
2109
2110    /// Retrieves a RocksDB property by name, for a specific column family.
2111    ///
2112    /// Full list of properties could be find
2113    /// [here](https://github.com/facebook/rocksdb/blob/08809f5e6cd9cc4bc3958dd4d59457ae78c76660/include/rocksdb/db.h#L428-L634).
2114    pub fn property_value_cf(
2115        &self,
2116        cf: &impl AsColumnFamilyRef,
2117        name: impl CStrLike,
2118    ) -> Result<Option<String>, Error> {
2119        Self::property_value_impl(
2120            name,
2121            |prop_name| unsafe {
2122                ffi::rocksdb_property_value_cf(self.inner.inner(), cf.inner(), prop_name)
2123            },
2124            |str_value| Ok(str_value.to_owned()),
2125        )
2126    }
2127
2128    fn parse_property_int_value(value: &str) -> Result<u64, Error> {
2129        value.parse::<u64>().map_err(|err| {
2130            Error::new(format!(
2131                "Failed to convert property value {value} to int: {err}"
2132            ))
2133        })
2134    }
2135
2136    /// Retrieves a RocksDB property and casts it to an integer.
2137    ///
2138    /// Full list of properties that return int values could be find
2139    /// [here](https://github.com/facebook/rocksdb/blob/08809f5e6cd9cc4bc3958dd4d59457ae78c76660/include/rocksdb/db.h#L654-L689).
2140    pub fn property_int_value(&self, name: impl CStrLike) -> Result<Option<u64>, Error> {
2141        Self::property_value_impl(
2142            name,
2143            |prop_name| unsafe { ffi::rocksdb_property_value(self.inner.inner(), prop_name) },
2144            Self::parse_property_int_value,
2145        )
2146    }
2147
2148    /// Retrieves a RocksDB property for a specific column family and casts it to an integer.
2149    ///
2150    /// Full list of properties that return int values could be find
2151    /// [here](https://github.com/facebook/rocksdb/blob/08809f5e6cd9cc4bc3958dd4d59457ae78c76660/include/rocksdb/db.h#L654-L689).
2152    pub fn property_int_value_cf(
2153        &self,
2154        cf: &impl AsColumnFamilyRef,
2155        name: impl CStrLike,
2156    ) -> Result<Option<u64>, Error> {
2157        Self::property_value_impl(
2158            name,
2159            |prop_name| unsafe {
2160                ffi::rocksdb_property_value_cf(self.inner.inner(), cf.inner(), prop_name)
2161            },
2162            Self::parse_property_int_value,
2163        )
2164    }
2165
2166    /// The sequence number of the most recent transaction.
2167    pub fn latest_sequence_number(&self) -> u64 {
2168        unsafe { ffi::rocksdb_get_latest_sequence_number(self.inner.inner()) }
2169    }
2170
2171    /// Return the approximate file system space used by keys in each ranges.
2172    ///
2173    /// Note that the returned sizes measure file system space usage, so
2174    /// if the user data compresses by a factor of ten, the returned
2175    /// sizes will be one-tenth the size of the corresponding user data size.
2176    ///
2177    /// Due to lack of abi, only data flushed to disk is taken into account.
2178    pub fn get_approximate_sizes(&self, ranges: &[Range]) -> Vec<u64> {
2179        self.get_approximate_sizes_cfopt(None::<&ColumnFamily>, ranges)
2180    }
2181
2182    pub fn get_approximate_sizes_cf(
2183        &self,
2184        cf: &impl AsColumnFamilyRef,
2185        ranges: &[Range],
2186    ) -> Vec<u64> {
2187        self.get_approximate_sizes_cfopt(Some(cf), ranges)
2188    }
2189
2190    fn get_approximate_sizes_cfopt(
2191        &self,
2192        cf: Option<&impl AsColumnFamilyRef>,
2193        ranges: &[Range],
2194    ) -> Vec<u64> {
2195        let start_keys: Vec<*const c_char> = ranges
2196            .iter()
2197            .map(|x| x.start_key.as_ptr() as *const c_char)
2198            .collect();
2199        let start_key_lens: Vec<_> = ranges.iter().map(|x| x.start_key.len()).collect();
2200        let end_keys: Vec<*const c_char> = ranges
2201            .iter()
2202            .map(|x| x.end_key.as_ptr() as *const c_char)
2203            .collect();
2204        let end_key_lens: Vec<_> = ranges.iter().map(|x| x.end_key.len()).collect();
2205        let mut sizes: Vec<u64> = vec![0; ranges.len()];
2206        let (n, start_key_ptr, start_key_len_ptr, end_key_ptr, end_key_len_ptr, size_ptr) = (
2207            ranges.len() as i32,
2208            start_keys.as_ptr(),
2209            start_key_lens.as_ptr(),
2210            end_keys.as_ptr(),
2211            end_key_lens.as_ptr(),
2212            sizes.as_mut_ptr(),
2213        );
2214        let mut err: *mut c_char = ptr::null_mut();
2215        match cf {
2216            None => unsafe {
2217                ffi::rocksdb_approximate_sizes(
2218                    self.inner.inner(),
2219                    n,
2220                    start_key_ptr,
2221                    start_key_len_ptr,
2222                    end_key_ptr,
2223                    end_key_len_ptr,
2224                    size_ptr,
2225                    &mut err,
2226                );
2227            },
2228            Some(cf) => unsafe {
2229                ffi::rocksdb_approximate_sizes_cf(
2230                    self.inner.inner(),
2231                    cf.inner(),
2232                    n,
2233                    start_key_ptr,
2234                    start_key_len_ptr,
2235                    end_key_ptr,
2236                    end_key_len_ptr,
2237                    size_ptr,
2238                    &mut err,
2239                );
2240            },
2241        }
2242        sizes
2243    }
2244
2245    /// Iterate over batches of write operations since a given sequence.
2246    ///
2247    /// Produce an iterator that will provide the batches of write operations
2248    /// that have occurred since the given sequence (see
2249    /// `latest_sequence_number()`). Use the provided iterator to retrieve each
2250    /// (`u64`, `WriteBatch`) tuple, and then gather the individual puts and
2251    /// deletes using the `WriteBatch::iterate()` function.
2252    ///
2253    /// Calling `get_updates_since()` with a sequence number that is out of
2254    /// bounds will return an error.
2255    pub fn get_updates_since(&self, seq_number: u64) -> Result<DBWALIterator, Error> {
2256        unsafe {
2257            // rocksdb_wal_readoptions_t does not appear to have any functions
2258            // for creating and destroying it; fortunately we can pass a nullptr
2259            // here to get the default behavior
2260            let opts: *const ffi::rocksdb_wal_readoptions_t = ptr::null();
2261            let iter = ffi_try!(ffi::rocksdb_get_updates_since(
2262                self.inner.inner(),
2263                seq_number,
2264                opts
2265            ));
2266            Ok(DBWALIterator {
2267                inner: iter,
2268                start_seq_number: seq_number,
2269            })
2270        }
2271    }
2272
2273    /// Tries to catch up with the primary by reading as much as possible from the
2274    /// log files.
2275    pub fn try_catch_up_with_primary(&self) -> Result<(), Error> {
2276        unsafe {
2277            ffi_try!(ffi::rocksdb_try_catch_up_with_primary(self.inner.inner()));
2278        }
2279        Ok(())
2280    }
2281
2282    /// Loads a list of external SST files created with SstFileWriter into the DB with default opts
2283    pub fn ingest_external_file<P: AsRef<Path>>(&self, paths: Vec<P>) -> Result<(), Error> {
2284        let opts = IngestExternalFileOptions::default();
2285        self.ingest_external_file_opts(&opts, paths)
2286    }
2287
2288    /// Loads a list of external SST files created with SstFileWriter into the DB
2289    pub fn ingest_external_file_opts<P: AsRef<Path>>(
2290        &self,
2291        opts: &IngestExternalFileOptions,
2292        paths: Vec<P>,
2293    ) -> Result<(), Error> {
2294        let paths_v: Vec<CString> = paths.iter().map(to_cpath).collect::<Result<Vec<_>, _>>()?;
2295        let cpaths: Vec<_> = paths_v.iter().map(|path| path.as_ptr()).collect();
2296
2297        self.ingest_external_file_raw(opts, &paths_v, &cpaths)
2298    }
2299
2300    /// Loads a list of external SST files created with SstFileWriter into the DB for given Column Family
2301    /// with default opts
2302    pub fn ingest_external_file_cf<P: AsRef<Path>>(
2303        &self,
2304        cf: &impl AsColumnFamilyRef,
2305        paths: Vec<P>,
2306    ) -> Result<(), Error> {
2307        let opts = IngestExternalFileOptions::default();
2308        self.ingest_external_file_cf_opts(cf, &opts, paths)
2309    }
2310
2311    /// Loads a list of external SST files created with SstFileWriter into the DB for given Column Family
2312    pub fn ingest_external_file_cf_opts<P: AsRef<Path>>(
2313        &self,
2314        cf: &impl AsColumnFamilyRef,
2315        opts: &IngestExternalFileOptions,
2316        paths: Vec<P>,
2317    ) -> Result<(), Error> {
2318        let paths_v: Vec<CString> = paths.iter().map(to_cpath).collect::<Result<Vec<_>, _>>()?;
2319        let cpaths: Vec<_> = paths_v.iter().map(|path| path.as_ptr()).collect();
2320
2321        self.ingest_external_file_raw_cf(cf, opts, &paths_v, &cpaths)
2322    }
2323
2324    fn ingest_external_file_raw(
2325        &self,
2326        opts: &IngestExternalFileOptions,
2327        paths_v: &[CString],
2328        cpaths: &[*const c_char],
2329    ) -> Result<(), Error> {
2330        unsafe {
2331            ffi_try!(ffi::rocksdb_ingest_external_file(
2332                self.inner.inner(),
2333                cpaths.as_ptr(),
2334                paths_v.len(),
2335                opts.inner.cast_const()
2336            ));
2337            Ok(())
2338        }
2339    }
2340
2341    fn ingest_external_file_raw_cf(
2342        &self,
2343        cf: &impl AsColumnFamilyRef,
2344        opts: &IngestExternalFileOptions,
2345        paths_v: &[CString],
2346        cpaths: &[*const c_char],
2347    ) -> Result<(), Error> {
2348        unsafe {
2349            ffi_try!(ffi::rocksdb_ingest_external_file_cf(
2350                self.inner.inner(),
2351                cf.inner(),
2352                cpaths.as_ptr(),
2353                paths_v.len(),
2354                opts.inner.cast_const()
2355            ));
2356            Ok(())
2357        }
2358    }
2359
2360    /// Obtains the LSM-tree meta data of the default column family of the DB
2361    pub fn get_column_family_metadata(&self) -> ColumnFamilyMetaData {
2362        unsafe {
2363            let ptr = ffi::rocksdb_get_column_family_metadata(self.inner.inner());
2364
2365            let metadata = ColumnFamilyMetaData {
2366                size: ffi::rocksdb_column_family_metadata_get_size(ptr),
2367                name: from_cstr(ffi::rocksdb_column_family_metadata_get_name(ptr)),
2368                file_count: ffi::rocksdb_column_family_metadata_get_file_count(ptr),
2369            };
2370
2371            // destroy
2372            ffi::rocksdb_column_family_metadata_destroy(ptr);
2373
2374            // return
2375            metadata
2376        }
2377    }
2378
2379    /// Obtains the LSM-tree meta data of the specified column family of the DB
2380    pub fn get_column_family_metadata_cf(
2381        &self,
2382        cf: &impl AsColumnFamilyRef,
2383    ) -> ColumnFamilyMetaData {
2384        unsafe {
2385            let ptr = ffi::rocksdb_get_column_family_metadata_cf(self.inner.inner(), cf.inner());
2386
2387            let metadata = ColumnFamilyMetaData {
2388                size: ffi::rocksdb_column_family_metadata_get_size(ptr),
2389                name: from_cstr(ffi::rocksdb_column_family_metadata_get_name(ptr)),
2390                file_count: ffi::rocksdb_column_family_metadata_get_file_count(ptr),
2391            };
2392
2393            // destroy
2394            ffi::rocksdb_column_family_metadata_destroy(ptr);
2395
2396            // return
2397            metadata
2398        }
2399    }
2400
2401    /// Returns a list of all table files with their level, start key
2402    /// and end key
2403    pub fn live_files(&self) -> Result<Vec<LiveFile>, Error> {
2404        unsafe {
2405            let files = ffi::rocksdb_livefiles(self.inner.inner());
2406            if files.is_null() {
2407                Err(Error::new("Could not get live files".to_owned()))
2408            } else {
2409                let n = ffi::rocksdb_livefiles_count(files);
2410
2411                let mut livefiles = Vec::with_capacity(n as usize);
2412                let mut key_size: usize = 0;
2413
2414                for i in 0..n {
2415                    let column_family_name =
2416                        from_cstr(ffi::rocksdb_livefiles_column_family_name(files, i));
2417                    let name = from_cstr(ffi::rocksdb_livefiles_name(files, i));
2418                    let size = ffi::rocksdb_livefiles_size(files, i);
2419                    let level = ffi::rocksdb_livefiles_level(files, i);
2420
2421                    // get smallest key inside file
2422                    let smallest_key = ffi::rocksdb_livefiles_smallestkey(files, i, &mut key_size);
2423                    let smallest_key = raw_data(smallest_key, key_size);
2424
2425                    // get largest key inside file
2426                    let largest_key = ffi::rocksdb_livefiles_largestkey(files, i, &mut key_size);
2427                    let largest_key = raw_data(largest_key, key_size);
2428
2429                    livefiles.push(LiveFile {
2430                        column_family_name,
2431                        name,
2432                        size,
2433                        level,
2434                        start_key: smallest_key,
2435                        end_key: largest_key,
2436                        num_entries: ffi::rocksdb_livefiles_entries(files, i),
2437                        num_deletions: ffi::rocksdb_livefiles_deletions(files, i),
2438                    });
2439                }
2440
2441                // destroy livefiles metadata(s)
2442                ffi::rocksdb_livefiles_destroy(files);
2443
2444                // return
2445                Ok(livefiles)
2446            }
2447        }
2448    }
2449
2450    /// Delete sst files whose keys are entirely in the given range.
2451    ///
2452    /// Could leave some keys in the range which are in files which are not
2453    /// entirely in the range.
2454    ///
2455    /// Note: L0 files are left regardless of whether they're in the range.
2456    ///
2457    /// SnapshotWithThreadModes before the delete might not see the data in the given range.
2458    pub fn delete_file_in_range<K: AsRef<[u8]>>(&self, from: K, to: K) -> Result<(), Error> {
2459        let from = from.as_ref();
2460        let to = to.as_ref();
2461        unsafe {
2462            ffi_try!(ffi::rocksdb_delete_file_in_range(
2463                self.inner.inner(),
2464                from.as_ptr() as *const c_char,
2465                from.len() as size_t,
2466                to.as_ptr() as *const c_char,
2467                to.len() as size_t,
2468            ));
2469            Ok(())
2470        }
2471    }
2472
2473    /// Same as `delete_file_in_range` but only for specific column family
2474    pub fn delete_file_in_range_cf<K: AsRef<[u8]>>(
2475        &self,
2476        cf: &impl AsColumnFamilyRef,
2477        from: K,
2478        to: K,
2479    ) -> Result<(), Error> {
2480        let from = from.as_ref();
2481        let to = to.as_ref();
2482        unsafe {
2483            ffi_try!(ffi::rocksdb_delete_file_in_range_cf(
2484                self.inner.inner(),
2485                cf.inner(),
2486                from.as_ptr() as *const c_char,
2487                from.len() as size_t,
2488                to.as_ptr() as *const c_char,
2489                to.len() as size_t,
2490            ));
2491            Ok(())
2492        }
2493    }
2494
2495    /// Request stopping background work, if wait is true wait until it's done.
2496    pub fn cancel_all_background_work(&self, wait: bool) {
2497        unsafe {
2498            ffi::rocksdb_cancel_all_background_work(self.inner.inner(), c_uchar::from(wait));
2499        }
2500    }
2501
2502    fn drop_column_family<C>(
2503        &self,
2504        cf_inner: *mut ffi::rocksdb_column_family_handle_t,
2505        cf: C,
2506    ) -> Result<(), Error> {
2507        unsafe {
2508            // first mark the column family as dropped
2509            ffi_try!(ffi::rocksdb_drop_column_family(
2510                self.inner.inner(),
2511                cf_inner
2512            ));
2513        }
2514        // then finally reclaim any resources (mem, files) by destroying the only single column
2515        // family handle by drop()-ing it
2516        drop(cf);
2517        Ok(())
2518    }
2519
2520    /// Increase the full_history_ts of column family. The new ts_low value should
2521    /// be newer than current full_history_ts value.
2522    /// If another thread updates full_history_ts_low concurrently to a higher
2523    /// timestamp than the requested ts_low, a try again error will be returned.
2524    pub fn increase_full_history_ts_low<S: AsRef<[u8]>>(
2525        &self,
2526        cf: &impl AsColumnFamilyRef,
2527        ts: S,
2528    ) -> Result<(), Error> {
2529        let ts = ts.as_ref();
2530        unsafe {
2531            ffi_try!(ffi::rocksdb_increase_full_history_ts_low(
2532                self.inner.inner(),
2533                cf.inner(),
2534                ts.as_ptr() as *const c_char,
2535                ts.len() as size_t,
2536            ));
2537            Ok(())
2538        }
2539    }
2540
2541    /// Get current full_history_ts value.
2542    pub fn get_full_history_ts_low(&self, cf: &impl AsColumnFamilyRef) -> Result<Vec<u8>, Error> {
2543        unsafe {
2544            let mut ts_lowlen = 0;
2545            let ts = ffi_try!(ffi::rocksdb_get_full_history_ts_low(
2546                self.inner.inner(),
2547                cf.inner(),
2548                &mut ts_lowlen,
2549            ));
2550
2551            if ts.is_null() {
2552                Err(Error::new("Could not get full_history_ts_low".to_owned()))
2553            } else {
2554                let mut vec = vec![0; ts_lowlen];
2555                ptr::copy_nonoverlapping(ts as *mut u8, vec.as_mut_ptr(), ts_lowlen);
2556                ffi::rocksdb_free(ts as *mut c_void);
2557                Ok(vec)
2558            }
2559        }
2560    }
2561
2562    /// Returns the DB identity. This is typically ASCII bytes, but that is not guaranteed.
2563    pub fn get_db_identity(&self) -> Result<Vec<u8>, Error> {
2564        unsafe {
2565            let mut length: usize = 0;
2566            let identity_ptr = ffi::rocksdb_get_db_identity(self.inner.inner(), &mut length);
2567            let identity_vec = raw_data(identity_ptr, length);
2568            ffi::rocksdb_free(identity_ptr as *mut c_void);
2569            // In RocksDB: get_db_identity copies a std::string so it should not fail, but
2570            // the API allows it to be overridden, so it might
2571            identity_vec.ok_or_else(|| Error::new("get_db_identity returned NULL".to_string()))
2572        }
2573    }
2574}
2575
2576impl<I: DBInner> DBCommon<SingleThreaded, I> {
2577    /// Creates column family with given name and options
2578    pub fn create_cf<N: AsRef<str>>(&mut self, name: N, opts: &Options) -> Result<(), Error> {
2579        let inner = self.create_inner_cf_handle(name.as_ref(), opts)?;
2580        self.cfs
2581            .cfs
2582            .insert(name.as_ref().to_string(), ColumnFamily { inner });
2583        Ok(())
2584    }
2585
2586    /// Drops the column family with the given name
2587    pub fn drop_cf(&mut self, name: &str) -> Result<(), Error> {
2588        if let Some(cf) = self.cfs.cfs.remove(name) {
2589            self.drop_column_family(cf.inner, cf)
2590        } else {
2591            Err(Error::new(format!("Invalid column family: {name}")))
2592        }
2593    }
2594
2595    /// Returns the underlying column family handle
2596    pub fn cf_handle(&self, name: &str) -> Option<&ColumnFamily> {
2597        self.cfs.cfs.get(name)
2598    }
2599}
2600
2601impl<I: DBInner> DBCommon<MultiThreaded, I> {
2602    /// Creates column family with given name and options
2603    pub fn create_cf<N: AsRef<str>>(&self, name: N, opts: &Options) -> Result<(), Error> {
2604        // Note that we acquire the cfs lock before inserting: otherwise we might race
2605        // another caller who observed the handle as missing.
2606        let mut cfs = self.cfs.cfs.write().unwrap();
2607        let inner = self.create_inner_cf_handle(name.as_ref(), opts)?;
2608        cfs.insert(
2609            name.as_ref().to_string(),
2610            Arc::new(UnboundColumnFamily { inner }),
2611        );
2612        Ok(())
2613    }
2614
2615    /// Drops the column family with the given name by internally locking the inner column
2616    /// family map. This avoids needing `&mut self` reference
2617    pub fn drop_cf(&self, name: &str) -> Result<(), Error> {
2618        if let Some(cf) = self.cfs.cfs.write().unwrap().remove(name) {
2619            self.drop_column_family(cf.inner, cf)
2620        } else {
2621            Err(Error::new(format!("Invalid column family: {name}")))
2622        }
2623    }
2624
2625    /// Returns the underlying column family handle
2626    pub fn cf_handle(&self, name: &str) -> Option<Arc<BoundColumnFamily>> {
2627        self.cfs
2628            .cfs
2629            .read()
2630            .unwrap()
2631            .get(name)
2632            .cloned()
2633            .map(UnboundColumnFamily::bound_column_family)
2634    }
2635}
2636
2637impl<T: ThreadMode, I: DBInner> Drop for DBCommon<T, I> {
2638    fn drop(&mut self) {
2639        self.cfs.drop_all_cfs_internal();
2640    }
2641}
2642
2643impl<T: ThreadMode, I: DBInner> fmt::Debug for DBCommon<T, I> {
2644    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2645        write!(f, "RocksDB {{ path: {:?} }}", self.path())
2646    }
2647}
2648
2649/// The metadata that describes a column family.
2650#[derive(Debug, Clone)]
2651pub struct ColumnFamilyMetaData {
2652    // The size of this column family in bytes, which is equal to the sum of
2653    // the file size of its "levels".
2654    pub size: u64,
2655    // The name of the column family.
2656    pub name: String,
2657    // The number of files in this column family.
2658    pub file_count: usize,
2659}
2660
2661/// The metadata that describes a SST file
2662#[derive(Debug, Clone)]
2663pub struct LiveFile {
2664    /// Name of the column family the file belongs to
2665    pub column_family_name: String,
2666    /// Name of the file
2667    pub name: String,
2668    /// Size of the file
2669    pub size: usize,
2670    /// Level at which this file resides
2671    pub level: i32,
2672    /// Smallest user defined key in the file
2673    pub start_key: Option<Vec<u8>>,
2674    /// Largest user defined key in the file
2675    pub end_key: Option<Vec<u8>>,
2676    /// Number of entries/alive keys in the file
2677    pub num_entries: u64,
2678    /// Number of deletions/tomb key(s) in the file
2679    pub num_deletions: u64,
2680}
2681
2682fn convert_options(opts: &[(&str, &str)]) -> Result<Vec<(CString, CString)>, Error> {
2683    opts.iter()
2684        .map(|(name, value)| {
2685            let cname = match CString::new(name.as_bytes()) {
2686                Ok(cname) => cname,
2687                Err(e) => return Err(Error::new(format!("Invalid option name `{e}`"))),
2688            };
2689            let cvalue = match CString::new(value.as_bytes()) {
2690                Ok(cvalue) => cvalue,
2691                Err(e) => return Err(Error::new(format!("Invalid option value: `{e}`"))),
2692            };
2693            Ok((cname, cvalue))
2694        })
2695        .collect()
2696}
2697
2698pub(crate) fn convert_values(
2699    values: Vec<*mut c_char>,
2700    values_sizes: Vec<usize>,
2701    errors: Vec<*mut c_char>,
2702) -> Vec<Result<Option<Vec<u8>>, Error>> {
2703    values
2704        .into_iter()
2705        .zip(values_sizes)
2706        .zip(errors)
2707        .map(|((v, s), e)| {
2708            if e.is_null() {
2709                let value = unsafe { crate::ffi_util::raw_data(v, s) };
2710                unsafe {
2711                    ffi::rocksdb_free(v as *mut c_void);
2712                }
2713                Ok(value)
2714            } else {
2715                Err(Error::new(crate::ffi_util::error_message(e)))
2716            }
2717        })
2718        .collect()
2719}