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