Skip to main content

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