rust_rocksdb/
db.rs

1// Copyright 2020 Tyler Neely
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14//
15
16use std::cell::RefCell;
17use std::collections::{BTreeMap, HashMap};
18use std::ffi::{CStr, CString};
19use std::fmt;
20use std::fs;
21use std::iter;
22use std::path::Path;
23use std::path::PathBuf;
24use std::ptr;
25use std::slice;
26use std::str;
27use std::sync::Arc;
28use std::time::Duration;
29
30use crate::column_family::ColumnFamilyTtl;
31use crate::ffi_util::CSlice;
32use crate::{
33    ColumnFamily, ColumnFamilyDescriptor, CompactOptions, DBIteratorWithThreadMode,
34    DBPinnableSlice, DBRawIteratorWithThreadMode, DBWALIterator, DEFAULT_COLUMN_FAMILY_NAME,
35    Direction, Error, FlushOptions, IngestExternalFileOptions, IteratorMode, Options, ReadOptions,
36    SnapshotWithThreadMode, WaitForCompactOptions, WriteBatch, WriteBatchWithIndex, WriteOptions,
37    column_family::{AsColumnFamilyRef, BoundColumnFamily, UnboundColumnFamily},
38    db_options::{ImportColumnFamilyOptions, OptionsMustOutliveDB},
39    ffi,
40    ffi_util::{
41        CStrLike, convert_rocksdb_error, from_cstr_and_free, from_cstr_without_free,
42        opt_bytes_to_ptr, raw_data, to_cpath,
43    },
44};
45use rust_librocksdb_sys::{
46    rocksdb_livefile_destroy, rocksdb_livefile_t, rocksdb_livefiles_destroy, rocksdb_livefiles_t,
47};
48
49use libc::{self, c_char, c_int, c_uchar, c_void, size_t};
50use parking_lot::RwLock;
51
52// Default options are kept per-thread to avoid re-allocating on every call while
53// also preventing cross-thread sharing. Some RocksDB option wrappers hold
54// pointers into internal buffers and are not safe to share across threads.
55// Using thread_local allows cheap reuse in the common "default options" path
56// without synchronization overhead. Callers who need non-defaults must pass
57// explicit options.
58thread_local! { static DEFAULT_READ_OPTS: ReadOptions = ReadOptions::default(); }
59thread_local! { static DEFAULT_WRITE_OPTS: WriteOptions = WriteOptions::default(); }
60thread_local! { static DEFAULT_FLUSH_OPTS: FlushOptions = FlushOptions::default(); }
61// Thread-local ReadOptions for hot prefix probes; preconfigured for prefix scans.
62thread_local! { static PREFIX_READ_OPTS: RefCell<ReadOptions> = RefCell::new({ let mut o = ReadOptions::default(); o.set_prefix_same_as_start(true); o }); }
63
64/// A range of keys, `start_key` is included, but not `end_key`.
65///
66/// You should make sure `end_key` is not less than `start_key`.
67pub struct Range<'a> {
68    start_key: &'a [u8],
69    end_key: &'a [u8],
70}
71
72impl<'a> Range<'a> {
73    pub fn new(start_key: &'a [u8], end_key: &'a [u8]) -> Range<'a> {
74        Range { start_key, end_key }
75    }
76}
77
78/// A reusable prefix probe that avoids per-call iterator creation/destruction.
79///
80/// Use this when performing many prefix existence checks in a tight loop.
81pub struct PrefixProber<'a, D: DBAccess> {
82    raw: DBRawIteratorWithThreadMode<'a, D>,
83}
84
85impl<D: DBAccess> PrefixProber<'_, D> {
86    /// Returns true if any key exists with the given prefix.
87    /// This performs a seek to the prefix and checks the current key.
88    pub fn exists(&mut self, prefix: &[u8]) -> Result<bool, Error> {
89        self.raw.seek(prefix);
90        if self.raw.valid()
91            && let Some(k) = self.raw.key()
92        {
93            return Ok(k.starts_with(prefix));
94        }
95        self.raw.status()?;
96        Ok(false)
97    }
98}
99
100/// Marker trait to specify single or multi threaded column family alternations for
101/// [`DBWithThreadMode<T>`]
102///
103/// This arrangement makes differences in self mutability and return type in
104/// some of `DBWithThreadMode` methods.
105///
106/// While being a marker trait to be generic over `DBWithThreadMode`, this trait
107/// also has a minimum set of not-encapsulated internal methods between
108/// [`SingleThreaded`] and [`MultiThreaded`].  These methods aren't expected to be
109/// called and defined externally.
110pub trait ThreadMode {
111    /// Internal implementation for storing column family handles
112    fn new_cf_map_internal(
113        cf_map: BTreeMap<String, *mut ffi::rocksdb_column_family_handle_t>,
114    ) -> Self;
115    /// Internal implementation for dropping column family handles
116    fn drop_all_cfs_internal(&mut self);
117}
118
119/// Actual marker type for the marker trait `ThreadMode`, which holds
120/// a collection of column families without synchronization primitive, providing
121/// no overhead for the single-threaded column family alternations. The other
122/// mode is [`MultiThreaded`].
123///
124/// See [`DB`] for more details, including performance implications for each mode
125pub struct SingleThreaded {
126    pub(crate) cfs: HashMap<String, ColumnFamily>,
127}
128
129/// Actual marker type for the marker trait `ThreadMode`, which holds
130/// a collection of column families wrapped in a RwLock to be mutated
131/// concurrently. The other mode is [`SingleThreaded`].
132///
133/// See [`DB`] for more details, including performance implications for each mode
134pub struct MultiThreaded {
135    pub(crate) cfs: RwLock<HashMap<String, Arc<UnboundColumnFamily>>>,
136}
137
138impl ThreadMode for SingleThreaded {
139    fn new_cf_map_internal(
140        cfs: BTreeMap<String, *mut ffi::rocksdb_column_family_handle_t>,
141    ) -> Self {
142        Self {
143            cfs: cfs
144                .into_iter()
145                .map(|(n, c)| (n, ColumnFamily { inner: c }))
146                .collect(),
147        }
148    }
149
150    fn drop_all_cfs_internal(&mut self) {
151        // Cause all ColumnFamily objects to be Drop::drop()-ed.
152        self.cfs.clear();
153    }
154}
155
156impl ThreadMode for MultiThreaded {
157    fn new_cf_map_internal(
158        cfs: BTreeMap<String, *mut ffi::rocksdb_column_family_handle_t>,
159    ) -> Self {
160        Self {
161            cfs: RwLock::new(
162                cfs.into_iter()
163                    .map(|(n, c)| (n, Arc::new(UnboundColumnFamily { inner: c })))
164                    .collect(),
165            ),
166        }
167    }
168
169    fn drop_all_cfs_internal(&mut self) {
170        // Cause all UnboundColumnFamily objects to be Drop::drop()-ed.
171        self.cfs.write().clear();
172    }
173}
174
175/// Get underlying `rocksdb_t`.
176pub trait DBInner {
177    fn inner(&self) -> *mut ffi::rocksdb_t;
178}
179
180/// A helper type to implement some common methods for [`DBWithThreadMode`]
181/// and [`OptimisticTransactionDB`].
182///
183/// [`OptimisticTransactionDB`]: crate::OptimisticTransactionDB
184pub struct DBCommon<T: ThreadMode, D: DBInner> {
185    pub(crate) inner: D,
186    cfs: T, // Column families are held differently depending on thread mode
187    path: PathBuf,
188    _outlive: Vec<OptionsMustOutliveDB>,
189}
190
191/// Minimal set of DB-related methods, intended to be generic over
192/// `DBWithThreadMode<T>`. Mainly used internally
193pub trait DBAccess {
194    unsafe fn create_snapshot(&self) -> *const ffi::rocksdb_snapshot_t;
195
196    unsafe fn release_snapshot(&self, snapshot: *const ffi::rocksdb_snapshot_t);
197
198    unsafe fn create_iterator(&self, readopts: &ReadOptions) -> *mut ffi::rocksdb_iterator_t;
199
200    unsafe fn create_iterator_cf(
201        &self,
202        cf_handle: *mut ffi::rocksdb_column_family_handle_t,
203        readopts: &ReadOptions,
204    ) -> *mut ffi::rocksdb_iterator_t;
205
206    fn get_opt<K: AsRef<[u8]>>(
207        &self,
208        key: K,
209        readopts: &ReadOptions,
210    ) -> Result<Option<Vec<u8>>, Error>;
211
212    fn get_cf_opt<K: AsRef<[u8]>>(
213        &self,
214        cf: &impl AsColumnFamilyRef,
215        key: K,
216        readopts: &ReadOptions,
217    ) -> Result<Option<Vec<u8>>, Error>;
218
219    fn get_pinned_opt<K: AsRef<[u8]>>(
220        &'_ self,
221        key: K,
222        readopts: &ReadOptions,
223    ) -> Result<Option<DBPinnableSlice<'_>>, Error>;
224
225    fn get_pinned_cf_opt<K: AsRef<[u8]>>(
226        &'_ self,
227        cf: &impl AsColumnFamilyRef,
228        key: K,
229        readopts: &ReadOptions,
230    ) -> Result<Option<DBPinnableSlice<'_>>, Error>;
231
232    fn multi_get_opt<K, I>(
233        &self,
234        keys: I,
235        readopts: &ReadOptions,
236    ) -> Vec<Result<Option<Vec<u8>>, Error>>
237    where
238        K: AsRef<[u8]>,
239        I: IntoIterator<Item = K>;
240
241    fn multi_get_cf_opt<'b, K, I, W>(
242        &self,
243        keys_cf: I,
244        readopts: &ReadOptions,
245    ) -> Vec<Result<Option<Vec<u8>>, Error>>
246    where
247        K: AsRef<[u8]>,
248        I: IntoIterator<Item = (&'b W, K)>,
249        W: AsColumnFamilyRef + 'b;
250}
251
252impl<T: ThreadMode, D: DBInner> DBAccess for DBCommon<T, D> {
253    unsafe fn create_snapshot(&self) -> *const ffi::rocksdb_snapshot_t {
254        unsafe { ffi::rocksdb_create_snapshot(self.inner.inner()) }
255    }
256
257    unsafe fn release_snapshot(&self, snapshot: *const ffi::rocksdb_snapshot_t) {
258        unsafe {
259            ffi::rocksdb_release_snapshot(self.inner.inner(), snapshot);
260        }
261    }
262
263    unsafe fn create_iterator(&self, readopts: &ReadOptions) -> *mut ffi::rocksdb_iterator_t {
264        unsafe { ffi::rocksdb_create_iterator(self.inner.inner(), readopts.inner) }
265    }
266
267    unsafe fn create_iterator_cf(
268        &self,
269        cf_handle: *mut ffi::rocksdb_column_family_handle_t,
270        readopts: &ReadOptions,
271    ) -> *mut ffi::rocksdb_iterator_t {
272        unsafe { ffi::rocksdb_create_iterator_cf(self.inner.inner(), readopts.inner, cf_handle) }
273    }
274
275    fn get_opt<K: AsRef<[u8]>>(
276        &self,
277        key: K,
278        readopts: &ReadOptions,
279    ) -> Result<Option<Vec<u8>>, Error> {
280        self.get_opt(key, readopts)
281    }
282
283    fn get_cf_opt<K: AsRef<[u8]>>(
284        &self,
285        cf: &impl AsColumnFamilyRef,
286        key: K,
287        readopts: &ReadOptions,
288    ) -> Result<Option<Vec<u8>>, Error> {
289        self.get_cf_opt(cf, key, readopts)
290    }
291
292    fn get_pinned_opt<K: AsRef<[u8]>>(
293        &'_ self,
294        key: K,
295        readopts: &ReadOptions,
296    ) -> Result<Option<DBPinnableSlice<'_>>, Error> {
297        self.get_pinned_opt(key, readopts)
298    }
299
300    fn get_pinned_cf_opt<K: AsRef<[u8]>>(
301        &'_ self,
302        cf: &impl AsColumnFamilyRef,
303        key: K,
304        readopts: &ReadOptions,
305    ) -> Result<Option<DBPinnableSlice<'_>>, Error> {
306        self.get_pinned_cf_opt(cf, key, readopts)
307    }
308
309    fn multi_get_opt<K, Iter>(
310        &self,
311        keys: Iter,
312        readopts: &ReadOptions,
313    ) -> Vec<Result<Option<Vec<u8>>, Error>>
314    where
315        K: AsRef<[u8]>,
316        Iter: IntoIterator<Item = K>,
317    {
318        self.multi_get_opt(keys, readopts)
319    }
320
321    fn multi_get_cf_opt<'b, K, Iter, W>(
322        &self,
323        keys_cf: Iter,
324        readopts: &ReadOptions,
325    ) -> Vec<Result<Option<Vec<u8>>, Error>>
326    where
327        K: AsRef<[u8]>,
328        Iter: IntoIterator<Item = (&'b W, K)>,
329        W: AsColumnFamilyRef + 'b,
330    {
331        self.multi_get_cf_opt(keys_cf, readopts)
332    }
333}
334
335pub struct DBWithThreadModeInner {
336    inner: *mut ffi::rocksdb_t,
337}
338
339impl DBInner for DBWithThreadModeInner {
340    fn inner(&self) -> *mut ffi::rocksdb_t {
341        self.inner
342    }
343}
344
345impl Drop for DBWithThreadModeInner {
346    fn drop(&mut self) {
347        unsafe {
348            ffi::rocksdb_close(self.inner);
349        }
350    }
351}
352
353/// A type alias to RocksDB database.
354///
355/// See crate level documentation for a simple usage example.
356/// See [`DBCommon`] for full list of methods.
357pub type DBWithThreadMode<T> = DBCommon<T, DBWithThreadModeInner>;
358
359/// A type alias to DB instance type with the single-threaded column family
360/// creations/deletions
361///
362/// # Compatibility and multi-threaded mode
363///
364/// Previously, [`DB`] was defined as a direct `struct`. Now, it's type-aliased for
365/// compatibility. Use `DBCommon<MultiThreaded>` for multi-threaded
366/// column family alternations.
367///
368/// # Limited performance implication for single-threaded mode
369///
370/// Even with [`SingleThreaded`], almost all of RocksDB operations is
371/// multi-threaded unless the underlying RocksDB instance is
372/// specifically configured otherwise. `SingleThreaded` only forces
373/// serialization of column family alternations by requiring `&mut self` of DB
374/// instance due to its wrapper implementation details.
375///
376/// # Multi-threaded mode
377///
378/// [`MultiThreaded`] can be appropriate for the situation of multi-threaded
379/// workload including multi-threaded column family alternations, costing the
380/// RwLock overhead inside `DB`.
381#[cfg(not(feature = "multi-threaded-cf"))]
382pub type DB = DBWithThreadMode<SingleThreaded>;
383
384#[cfg(feature = "multi-threaded-cf")]
385pub type DB = DBWithThreadMode<MultiThreaded>;
386
387// Safety note: auto-implementing Send on most db-related types is prevented by the inner FFI
388// pointer. In most cases, however, this pointer is Send-safe because it is never aliased and
389// rocksdb internally does not rely on thread-local information for its user-exposed types.
390unsafe impl<T: ThreadMode + Send, I: DBInner> Send for DBCommon<T, I> {}
391
392// Sync is similarly safe for many types because they do not expose interior mutability, and their
393// use within the rocksdb library is generally behind a const reference
394unsafe impl<T: ThreadMode, I: DBInner> Sync for DBCommon<T, I> {}
395
396// Specifies whether open DB for read only.
397enum AccessType<'a> {
398    ReadWrite,
399    ReadOnly { error_if_log_file_exist: bool },
400    Secondary { secondary_path: &'a Path },
401    WithTTL { ttl: Duration },
402}
403
404/// Methods of `DBWithThreadMode`.
405impl<T: ThreadMode> DBWithThreadMode<T> {
406    /// Opens a database with default options.
407    pub fn open_default<P: AsRef<Path>>(path: P) -> Result<Self, Error> {
408        let mut opts = Options::default();
409        opts.create_if_missing(true);
410        Self::open(&opts, path)
411    }
412
413    /// Opens the database with the specified options.
414    pub fn open<P: AsRef<Path>>(opts: &Options, path: P) -> Result<Self, Error> {
415        Self::open_cf(opts, path, None::<&str>)
416    }
417
418    /// Opens the database for read only with the specified options.
419    pub fn open_for_read_only<P: AsRef<Path>>(
420        opts: &Options,
421        path: P,
422        error_if_log_file_exist: bool,
423    ) -> Result<Self, Error> {
424        Self::open_cf_for_read_only(opts, path, None::<&str>, error_if_log_file_exist)
425    }
426
427    /// Opens the database as a secondary.
428    pub fn open_as_secondary<P: AsRef<Path>>(
429        opts: &Options,
430        primary_path: P,
431        secondary_path: P,
432    ) -> Result<Self, Error> {
433        Self::open_cf_as_secondary(opts, primary_path, secondary_path, None::<&str>)
434    }
435
436    /// Opens the database with a Time to Live compaction filter.
437    ///
438    /// This applies the given `ttl` to all column families created without an explicit TTL.
439    /// See [`DB::open_cf_descriptors_with_ttl`] for more control over individual column family TTLs.
440    pub fn open_with_ttl<P: AsRef<Path>>(
441        opts: &Options,
442        path: P,
443        ttl: Duration,
444    ) -> Result<Self, Error> {
445        Self::open_cf_descriptors_with_ttl(opts, path, std::iter::empty(), ttl)
446    }
447
448    /// Opens the database with a Time to Live compaction filter and column family names.
449    ///
450    /// Column families opened using this function will be created with default `Options`.
451    pub fn open_cf_with_ttl<P, I, N>(
452        opts: &Options,
453        path: P,
454        cfs: I,
455        ttl: Duration,
456    ) -> Result<Self, Error>
457    where
458        P: AsRef<Path>,
459        I: IntoIterator<Item = N>,
460        N: AsRef<str>,
461    {
462        let cfs = cfs
463            .into_iter()
464            .map(|name| ColumnFamilyDescriptor::new(name.as_ref(), Options::default()));
465
466        Self::open_cf_descriptors_with_ttl(opts, path, cfs, ttl)
467    }
468
469    /// Opens a database with the given database with a Time to Live compaction filter and
470    /// column family descriptors.
471    ///
472    /// Applies the provided `ttl` as the default TTL for all column families.
473    /// Column families will inherit this TTL by default, unless their descriptor explicitly
474    /// sets a different TTL using [`ColumnFamilyTtl::Duration`] or opts out using [`ColumnFamilyTtl::Disabled`].
475    ///
476    /// *NOTE*: The `default` column family is opened with `Options::default()` unless
477    /// explicitly configured within the `cfs` iterator.
478    /// To customize the `default` column family's options, include a `ColumnFamilyDescriptor`
479    /// with the name "default" in the `cfs` iterator.
480    ///
481    /// If you want to open `default` cf with different options, set them explicitly in `cfs`.
482    pub fn open_cf_descriptors_with_ttl<P, I>(
483        opts: &Options,
484        path: P,
485        cfs: I,
486        ttl: Duration,
487    ) -> Result<Self, Error>
488    where
489        P: AsRef<Path>,
490        I: IntoIterator<Item = ColumnFamilyDescriptor>,
491    {
492        Self::open_cf_descriptors_internal(opts, path, cfs, &AccessType::WithTTL { ttl })
493    }
494
495    /// Opens a database with the given database options and column family names.
496    ///
497    /// Column families opened using this function will be created with default `Options`.
498    pub fn open_cf<P, I, N>(opts: &Options, path: P, cfs: I) -> Result<Self, Error>
499    where
500        P: AsRef<Path>,
501        I: IntoIterator<Item = N>,
502        N: AsRef<str>,
503    {
504        let cfs = cfs
505            .into_iter()
506            .map(|name| ColumnFamilyDescriptor::new(name.as_ref(), Options::default()));
507
508        Self::open_cf_descriptors_internal(opts, path, cfs, &AccessType::ReadWrite)
509    }
510
511    /// Opens a database with the given database options and column family names.
512    ///
513    /// Column families opened using given `Options`.
514    pub fn open_cf_with_opts<P, I, N>(opts: &Options, path: P, cfs: I) -> Result<Self, Error>
515    where
516        P: AsRef<Path>,
517        I: IntoIterator<Item = (N, Options)>,
518        N: AsRef<str>,
519    {
520        let cfs = cfs
521            .into_iter()
522            .map(|(name, opts)| ColumnFamilyDescriptor::new(name.as_ref(), opts));
523
524        Self::open_cf_descriptors(opts, path, cfs)
525    }
526
527    /// Opens a database for read only with the given database options and column family names.
528    /// *NOTE*: `default` column family is opened with `Options::default()`.
529    /// If you want to open `default` cf with different options, set them explicitly in `cfs`.
530    pub fn open_cf_for_read_only<P, I, N>(
531        opts: &Options,
532        path: P,
533        cfs: I,
534        error_if_log_file_exist: bool,
535    ) -> Result<Self, Error>
536    where
537        P: AsRef<Path>,
538        I: IntoIterator<Item = N>,
539        N: AsRef<str>,
540    {
541        let cfs = cfs
542            .into_iter()
543            .map(|name| ColumnFamilyDescriptor::new(name.as_ref(), Options::default()));
544
545        Self::open_cf_descriptors_internal(
546            opts,
547            path,
548            cfs,
549            &AccessType::ReadOnly {
550                error_if_log_file_exist,
551            },
552        )
553    }
554
555    /// Opens a database for read only with the given database options and column family names.
556    /// *NOTE*: `default` column family is opened with `Options::default()`.
557    /// If you want to open `default` cf with different options, set them explicitly in `cfs`.
558    pub fn open_cf_with_opts_for_read_only<P, I, N>(
559        db_opts: &Options,
560        path: P,
561        cfs: I,
562        error_if_log_file_exist: bool,
563    ) -> Result<Self, Error>
564    where
565        P: AsRef<Path>,
566        I: IntoIterator<Item = (N, Options)>,
567        N: AsRef<str>,
568    {
569        let cfs = cfs
570            .into_iter()
571            .map(|(name, cf_opts)| ColumnFamilyDescriptor::new(name.as_ref(), cf_opts));
572
573        Self::open_cf_descriptors_internal(
574            db_opts,
575            path,
576            cfs,
577            &AccessType::ReadOnly {
578                error_if_log_file_exist,
579            },
580        )
581    }
582
583    /// Opens a database for ready only with the given database options and
584    /// column family descriptors.
585    /// *NOTE*: `default` column family is opened with `Options::default()`.
586    /// If you want to open `default` cf with different options, set them explicitly in `cfs`.
587    pub fn open_cf_descriptors_read_only<P, I>(
588        opts: &Options,
589        path: P,
590        cfs: I,
591        error_if_log_file_exist: bool,
592    ) -> Result<Self, Error>
593    where
594        P: AsRef<Path>,
595        I: IntoIterator<Item = ColumnFamilyDescriptor>,
596    {
597        Self::open_cf_descriptors_internal(
598            opts,
599            path,
600            cfs,
601            &AccessType::ReadOnly {
602                error_if_log_file_exist,
603            },
604        )
605    }
606
607    /// Opens the database as a secondary with the given database options and column family names.
608    /// *NOTE*: `default` column family is opened with `Options::default()`.
609    /// If you want to open `default` cf with different options, set them explicitly in `cfs`.
610    pub fn open_cf_as_secondary<P, I, N>(
611        opts: &Options,
612        primary_path: P,
613        secondary_path: P,
614        cfs: I,
615    ) -> Result<Self, Error>
616    where
617        P: AsRef<Path>,
618        I: IntoIterator<Item = N>,
619        N: AsRef<str>,
620    {
621        let cfs = cfs
622            .into_iter()
623            .map(|name| ColumnFamilyDescriptor::new(name.as_ref(), Options::default()));
624
625        Self::open_cf_descriptors_internal(
626            opts,
627            primary_path,
628            cfs,
629            &AccessType::Secondary {
630                secondary_path: secondary_path.as_ref(),
631            },
632        )
633    }
634
635    /// Opens the database as a secondary with the given database options and
636    /// column family descriptors.
637    /// *NOTE*: `default` column family is opened with `Options::default()`.
638    /// If you want to open `default` cf with different options, set them explicitly in `cfs`.
639    pub fn open_cf_descriptors_as_secondary<P, I>(
640        opts: &Options,
641        path: P,
642        secondary_path: P,
643        cfs: I,
644    ) -> Result<Self, Error>
645    where
646        P: AsRef<Path>,
647        I: IntoIterator<Item = ColumnFamilyDescriptor>,
648    {
649        Self::open_cf_descriptors_internal(
650            opts,
651            path,
652            cfs,
653            &AccessType::Secondary {
654                secondary_path: secondary_path.as_ref(),
655            },
656        )
657    }
658
659    /// Opens a database with the given database options and column family descriptors.
660    /// *NOTE*: `default` column family is opened with `Options::default()`.
661    /// If you want to open `default` cf with different options, set them explicitly in `cfs`.
662    pub fn open_cf_descriptors<P, I>(opts: &Options, path: P, cfs: I) -> Result<Self, Error>
663    where
664        P: AsRef<Path>,
665        I: IntoIterator<Item = ColumnFamilyDescriptor>,
666    {
667        Self::open_cf_descriptors_internal(opts, path, cfs, &AccessType::ReadWrite)
668    }
669
670    /// Internal implementation for opening RocksDB.
671    fn open_cf_descriptors_internal<P, I>(
672        opts: &Options,
673        path: P,
674        cfs: I,
675        access_type: &AccessType,
676    ) -> Result<Self, Error>
677    where
678        P: AsRef<Path>,
679        I: IntoIterator<Item = ColumnFamilyDescriptor>,
680    {
681        let cfs: Vec<_> = cfs.into_iter().collect();
682        let outlive = iter::once(opts.outlive.clone())
683            .chain(cfs.iter().map(|cf| cf.options.outlive.clone()))
684            .collect();
685
686        let cpath = to_cpath(&path)?;
687
688        if let Err(e) = fs::create_dir_all(&path) {
689            return Err(Error::new(format!(
690                "Failed to create RocksDB directory: `{e:?}`."
691            )));
692        }
693
694        let db: *mut ffi::rocksdb_t;
695        let mut cf_map = BTreeMap::new();
696
697        if cfs.is_empty() {
698            db = Self::open_raw(opts, &cpath, access_type)?;
699        } else {
700            let mut cfs_v = cfs;
701            // Always open the default column family.
702            if !cfs_v.iter().any(|cf| cf.name == DEFAULT_COLUMN_FAMILY_NAME) {
703                cfs_v.push(ColumnFamilyDescriptor {
704                    name: String::from(DEFAULT_COLUMN_FAMILY_NAME),
705                    options: Options::default(),
706                    ttl: ColumnFamilyTtl::SameAsDb,
707                });
708            }
709            // We need to store our CStrings in an intermediate vector
710            // so that their pointers remain valid.
711            let c_cfs: Vec<CString> = cfs_v
712                .iter()
713                .map(|cf| CString::new(cf.name.as_bytes()).unwrap())
714                .collect();
715
716            let cfnames: Vec<_> = c_cfs.iter().map(|cf| cf.as_ptr()).collect();
717
718            // These handles will be populated by DB.
719            let mut cfhandles: Vec<_> = cfs_v.iter().map(|_| ptr::null_mut()).collect();
720
721            let cfopts: Vec<_> = cfs_v
722                .iter()
723                .map(|cf| cf.options.inner.cast_const())
724                .collect();
725
726            db = Self::open_cf_raw(
727                opts,
728                &cpath,
729                &cfs_v,
730                &cfnames,
731                &cfopts,
732                &mut cfhandles,
733                access_type,
734            )?;
735            for handle in &cfhandles {
736                if handle.is_null() {
737                    return Err(Error::new(
738                        "Received null column family handle from DB.".to_owned(),
739                    ));
740                }
741            }
742
743            for (cf_desc, inner) in cfs_v.iter().zip(cfhandles) {
744                cf_map.insert(cf_desc.name.clone(), inner);
745            }
746        }
747
748        if db.is_null() {
749            return Err(Error::new("Could not initialize database.".to_owned()));
750        }
751
752        Ok(Self {
753            inner: DBWithThreadModeInner { inner: db },
754            path: path.as_ref().to_path_buf(),
755            cfs: T::new_cf_map_internal(cf_map),
756            _outlive: outlive,
757        })
758    }
759
760    fn open_raw(
761        opts: &Options,
762        cpath: &CString,
763        access_type: &AccessType,
764    ) -> Result<*mut ffi::rocksdb_t, Error> {
765        let db = unsafe {
766            match *access_type {
767                AccessType::ReadOnly {
768                    error_if_log_file_exist,
769                } => ffi_try!(ffi::rocksdb_open_for_read_only(
770                    opts.inner,
771                    cpath.as_ptr(),
772                    c_uchar::from(error_if_log_file_exist),
773                )),
774                AccessType::ReadWrite => {
775                    ffi_try!(ffi::rocksdb_open(opts.inner, cpath.as_ptr()))
776                }
777                AccessType::Secondary { secondary_path } => {
778                    ffi_try!(ffi::rocksdb_open_as_secondary(
779                        opts.inner,
780                        cpath.as_ptr(),
781                        to_cpath(secondary_path)?.as_ptr(),
782                    ))
783                }
784                AccessType::WithTTL { ttl } => ffi_try!(ffi::rocksdb_open_with_ttl(
785                    opts.inner,
786                    cpath.as_ptr(),
787                    ttl.as_secs() as c_int,
788                )),
789            }
790        };
791        Ok(db)
792    }
793
794    #[allow(clippy::pedantic)]
795    fn open_cf_raw(
796        opts: &Options,
797        cpath: &CString,
798        cfs_v: &[ColumnFamilyDescriptor],
799        cfnames: &[*const c_char],
800        cfopts: &[*const ffi::rocksdb_options_t],
801        cfhandles: &mut [*mut ffi::rocksdb_column_family_handle_t],
802        access_type: &AccessType,
803    ) -> Result<*mut ffi::rocksdb_t, Error> {
804        let db = unsafe {
805            match *access_type {
806                AccessType::ReadOnly {
807                    error_if_log_file_exist,
808                } => ffi_try!(ffi::rocksdb_open_for_read_only_column_families(
809                    opts.inner,
810                    cpath.as_ptr(),
811                    cfs_v.len() as c_int,
812                    cfnames.as_ptr(),
813                    cfopts.as_ptr(),
814                    cfhandles.as_mut_ptr(),
815                    c_uchar::from(error_if_log_file_exist),
816                )),
817                AccessType::ReadWrite => ffi_try!(ffi::rocksdb_open_column_families(
818                    opts.inner,
819                    cpath.as_ptr(),
820                    cfs_v.len() as c_int,
821                    cfnames.as_ptr(),
822                    cfopts.as_ptr(),
823                    cfhandles.as_mut_ptr(),
824                )),
825                AccessType::Secondary { secondary_path } => {
826                    ffi_try!(ffi::rocksdb_open_as_secondary_column_families(
827                        opts.inner,
828                        cpath.as_ptr(),
829                        to_cpath(secondary_path)?.as_ptr(),
830                        cfs_v.len() as c_int,
831                        cfnames.as_ptr(),
832                        cfopts.as_ptr(),
833                        cfhandles.as_mut_ptr(),
834                    ))
835                }
836                AccessType::WithTTL { ttl } => {
837                    let ttls: Vec<_> = cfs_v
838                        .iter()
839                        .map(|cf| match cf.ttl {
840                            ColumnFamilyTtl::Disabled => i32::MAX,
841                            ColumnFamilyTtl::Duration(duration) => duration.as_secs() as i32,
842                            ColumnFamilyTtl::SameAsDb => ttl.as_secs() as i32,
843                        })
844                        .collect();
845
846                    ffi_try!(ffi::rocksdb_open_column_families_with_ttl(
847                        opts.inner,
848                        cpath.as_ptr(),
849                        cfs_v.len() as c_int,
850                        cfnames.as_ptr(),
851                        cfopts.as_ptr(),
852                        cfhandles.as_mut_ptr(),
853                        ttls.as_ptr(),
854                    ))
855                }
856            }
857        };
858        Ok(db)
859    }
860
861    /// Removes the database entries in the range `["from", "to")` using given write options.
862    pub fn delete_range_cf_opt<K: AsRef<[u8]>>(
863        &self,
864        cf: &impl AsColumnFamilyRef,
865        from: K,
866        to: K,
867        writeopts: &WriteOptions,
868    ) -> Result<(), Error> {
869        let from = from.as_ref();
870        let to = to.as_ref();
871
872        unsafe {
873            ffi_try!(ffi::rocksdb_delete_range_cf(
874                self.inner.inner(),
875                writeopts.inner,
876                cf.inner(),
877                from.as_ptr() as *const c_char,
878                from.len() as size_t,
879                to.as_ptr() as *const c_char,
880                to.len() as size_t,
881            ));
882            Ok(())
883        }
884    }
885
886    /// Removes the database entries in the range `["from", "to")` using default write options.
887    pub fn delete_range_cf<K: AsRef<[u8]>>(
888        &self,
889        cf: &impl AsColumnFamilyRef,
890        from: K,
891        to: K,
892    ) -> Result<(), Error> {
893        DEFAULT_WRITE_OPTS.with(|opts| self.delete_range_cf_opt(cf, from, to, opts))
894    }
895
896    pub fn write_opt(&self, batch: &WriteBatch, writeopts: &WriteOptions) -> Result<(), Error> {
897        unsafe {
898            ffi_try!(ffi::rocksdb_write(
899                self.inner.inner(),
900                writeopts.inner,
901                batch.inner
902            ));
903        }
904        Ok(())
905    }
906
907    pub fn write(&self, batch: &WriteBatch) -> Result<(), Error> {
908        DEFAULT_WRITE_OPTS.with(|opts| self.write_opt(batch, opts))
909    }
910
911    pub fn write_without_wal(&self, batch: &WriteBatch) -> Result<(), Error> {
912        let mut wo = WriteOptions::new();
913        wo.disable_wal(true);
914        self.write_opt(batch, &wo)
915    }
916
917    pub fn write_wbwi(&self, wbwi: &WriteBatchWithIndex) -> Result<(), Error> {
918        DEFAULT_WRITE_OPTS.with(|opts| self.write_wbwi_opt(wbwi, opts))
919    }
920
921    pub fn write_wbwi_opt(
922        &self,
923        wbwi: &WriteBatchWithIndex,
924        writeopts: &WriteOptions,
925    ) -> Result<(), Error> {
926        unsafe {
927            ffi_try!(ffi::rocksdb_write_writebatch_wi(
928                self.inner.inner(),
929                writeopts.inner,
930                wbwi.inner
931            ));
932
933            Ok(())
934        }
935    }
936
937    /// Suspend deleting obsolete files. Compactions will continue to occur,
938    /// but no obsolete files will be deleted. To resume file deletions, each
939    /// call to disable_file_deletions() must be matched by a subsequent call to
940    /// enable_file_deletions(). For more details, see enable_file_deletions().
941    pub fn disable_file_deletions(&self) -> Result<(), Error> {
942        unsafe {
943            ffi_try!(ffi::rocksdb_disable_file_deletions(self.inner.inner()));
944        }
945        Ok(())
946    }
947
948    /// Resume deleting obsolete files, following up on `disable_file_deletions()`.
949    ///
950    /// File deletions disabling and enabling is not controlled by a binary flag,
951    /// instead it's represented as a counter to allow different callers to
952    /// independently disable file deletion. Disabling file deletion can be
953    /// critical for operations like making a backup. So the counter implementation
954    /// makes the file deletion disabled as long as there is one caller requesting
955    /// so, and only when every caller agrees to re-enable file deletion, it will
956    /// be enabled. Two threads can call this method concurrently without
957    /// synchronization -- i.e., file deletions will be enabled only after both
958    /// threads call enable_file_deletions()
959    pub fn enable_file_deletions(&self) -> Result<(), Error> {
960        unsafe {
961            ffi_try!(ffi::rocksdb_enable_file_deletions(self.inner.inner()));
962        }
963        Ok(())
964    }
965}
966
967/// Common methods of `DBWithThreadMode` and `OptimisticTransactionDB`.
968impl<T: ThreadMode, D: DBInner> DBCommon<T, D> {
969    pub(crate) fn new(inner: D, cfs: T, path: PathBuf, outlive: Vec<OptionsMustOutliveDB>) -> Self {
970        Self {
971            inner,
972            cfs,
973            path,
974            _outlive: outlive,
975        }
976    }
977
978    pub fn list_cf<P: AsRef<Path>>(opts: &Options, path: P) -> Result<Vec<String>, Error> {
979        let cpath = to_cpath(path)?;
980        let mut length = 0;
981
982        unsafe {
983            let ptr = ffi_try!(ffi::rocksdb_list_column_families(
984                opts.inner,
985                cpath.as_ptr(),
986                &raw mut length,
987            ));
988
989            let vec = slice::from_raw_parts(ptr, length)
990                .iter()
991                .map(|ptr| from_cstr_without_free(*ptr))
992                .collect();
993            ffi::rocksdb_list_column_families_destroy(ptr, length);
994            Ok(vec)
995        }
996    }
997
998    pub fn destroy<P: AsRef<Path>>(opts: &Options, path: P) -> Result<(), Error> {
999        let cpath = to_cpath(path)?;
1000        unsafe {
1001            ffi_try!(ffi::rocksdb_destroy_db(opts.inner, cpath.as_ptr()));
1002        }
1003        Ok(())
1004    }
1005
1006    pub fn repair<P: AsRef<Path>>(opts: &Options, path: P) -> Result<(), Error> {
1007        let cpath = to_cpath(path)?;
1008        unsafe {
1009            ffi_try!(ffi::rocksdb_repair_db(opts.inner, cpath.as_ptr()));
1010        }
1011        Ok(())
1012    }
1013
1014    pub fn path(&self) -> &Path {
1015        self.path.as_path()
1016    }
1017
1018    /// Flushes the WAL buffer. If `sync` is set to `true`, also syncs
1019    /// the data to disk.
1020    pub fn flush_wal(&self, sync: bool) -> Result<(), Error> {
1021        unsafe {
1022            ffi_try!(ffi::rocksdb_flush_wal(
1023                self.inner.inner(),
1024                c_uchar::from(sync)
1025            ));
1026        }
1027        Ok(())
1028    }
1029
1030    /// Flushes database memtables to SST files on the disk.
1031    pub fn flush_opt(&self, flushopts: &FlushOptions) -> Result<(), Error> {
1032        unsafe {
1033            ffi_try!(ffi::rocksdb_flush(self.inner.inner(), flushopts.inner));
1034        }
1035        Ok(())
1036    }
1037
1038    /// Flushes database memtables to SST files on the disk using default options.
1039    pub fn flush(&self) -> Result<(), Error> {
1040        self.flush_opt(&FlushOptions::default())
1041    }
1042
1043    /// Flushes database memtables to SST files on the disk for a given column family.
1044    pub fn flush_cf_opt(
1045        &self,
1046        cf: &impl AsColumnFamilyRef,
1047        flushopts: &FlushOptions,
1048    ) -> Result<(), Error> {
1049        unsafe {
1050            ffi_try!(ffi::rocksdb_flush_cf(
1051                self.inner.inner(),
1052                flushopts.inner,
1053                cf.inner()
1054            ));
1055        }
1056        Ok(())
1057    }
1058
1059    /// Flushes multiple column families.
1060    ///
1061    /// If atomic flush is not enabled, it is equivalent to calling flush_cf multiple times.
1062    /// If atomic flush is enabled, it will flush all column families specified in `cfs` up to the latest sequence
1063    /// number at the time when flush is requested.
1064    pub fn flush_cfs_opt(
1065        &self,
1066        cfs: &[&impl AsColumnFamilyRef],
1067        opts: &FlushOptions,
1068    ) -> Result<(), Error> {
1069        let mut cfs = cfs.iter().map(|cf| cf.inner()).collect::<Vec<_>>();
1070        unsafe {
1071            ffi_try!(ffi::rocksdb_flush_cfs(
1072                self.inner.inner(),
1073                opts.inner,
1074                cfs.as_mut_ptr(),
1075                cfs.len() as libc::c_int,
1076            ));
1077        }
1078        Ok(())
1079    }
1080
1081    /// Flushes database memtables to SST files on the disk for a given column family using default
1082    /// options.
1083    pub fn flush_cf(&self, cf: &impl AsColumnFamilyRef) -> Result<(), Error> {
1084        DEFAULT_FLUSH_OPTS.with(|opts| self.flush_cf_opt(cf, opts))
1085    }
1086
1087    /// Return the bytes associated with a key value with read options. If you only intend to use
1088    /// the vector returned temporarily, consider using [`get_pinned_opt`](#method.get_pinned_opt)
1089    /// to avoid unnecessary memory copy.
1090    pub fn get_opt<K: AsRef<[u8]>>(
1091        &self,
1092        key: K,
1093        readopts: &ReadOptions,
1094    ) -> Result<Option<Vec<u8>>, Error> {
1095        self.get_pinned_opt(key, readopts)
1096            .map(|x| x.map(|v| v.as_ref().to_vec()))
1097    }
1098
1099    /// Return the bytes associated with a key value. If you only intend to use the vector returned
1100    /// temporarily, consider using [`get_pinned`](#method.get_pinned) to avoid unnecessary memory
1101    /// copy.
1102    pub fn get<K: AsRef<[u8]>>(&self, key: K) -> Result<Option<Vec<u8>>, Error> {
1103        DEFAULT_READ_OPTS.with(|opts| self.get_opt(key.as_ref(), opts))
1104    }
1105
1106    /// Return the bytes associated with a key value and the given column family with read options.
1107    /// If you only intend to use the vector returned temporarily, consider using
1108    /// [`get_pinned_cf_opt`](#method.get_pinned_cf_opt) to avoid unnecessary memory.
1109    pub fn get_cf_opt<K: AsRef<[u8]>>(
1110        &self,
1111        cf: &impl AsColumnFamilyRef,
1112        key: K,
1113        readopts: &ReadOptions,
1114    ) -> Result<Option<Vec<u8>>, Error> {
1115        self.get_pinned_cf_opt(cf, key, readopts)
1116            .map(|x| x.map(|v| v.as_ref().to_vec()))
1117    }
1118
1119    /// Return the bytes associated with a key value and the given column family. If you only
1120    /// intend to use the vector returned temporarily, consider using
1121    /// [`get_pinned_cf`](#method.get_pinned_cf) to avoid unnecessary memory.
1122    pub fn get_cf<K: AsRef<[u8]>>(
1123        &self,
1124        cf: &impl AsColumnFamilyRef,
1125        key: K,
1126    ) -> Result<Option<Vec<u8>>, Error> {
1127        DEFAULT_READ_OPTS.with(|opts| self.get_cf_opt(cf, key.as_ref(), opts))
1128    }
1129
1130    /// Return the value associated with a key using RocksDB's PinnableSlice
1131    /// so as to avoid unnecessary memory copy.
1132    pub fn get_pinned_opt<K: AsRef<[u8]>>(
1133        &'_ self,
1134        key: K,
1135        readopts: &ReadOptions,
1136    ) -> Result<Option<DBPinnableSlice<'_>>, Error> {
1137        if readopts.inner.is_null() {
1138            return Err(Error::new(
1139                "Unable to create RocksDB read options. This is a fairly trivial call, and its \
1140                 failure may be indicative of a mis-compiled or mis-loaded RocksDB library."
1141                    .to_owned(),
1142            ));
1143        }
1144
1145        let key = key.as_ref();
1146        unsafe {
1147            let val = ffi_try!(ffi::rocksdb_get_pinned(
1148                self.inner.inner(),
1149                readopts.inner,
1150                key.as_ptr() as *const c_char,
1151                key.len() as size_t,
1152            ));
1153            if val.is_null() {
1154                Ok(None)
1155            } else {
1156                Ok(Some(DBPinnableSlice::from_c(val)))
1157            }
1158        }
1159    }
1160
1161    /// Return the value associated with a key using RocksDB's PinnableSlice
1162    /// so as to avoid unnecessary memory copy. Similar to get_pinned_opt but
1163    /// leverages default options.
1164    pub fn get_pinned<K: AsRef<[u8]>>(
1165        &'_ self,
1166        key: K,
1167    ) -> Result<Option<DBPinnableSlice<'_>>, Error> {
1168        DEFAULT_READ_OPTS.with(|opts| self.get_pinned_opt(key, opts))
1169    }
1170
1171    /// Return the value associated with a key using RocksDB's PinnableSlice
1172    /// so as to avoid unnecessary memory copy. Similar to get_pinned_opt but
1173    /// allows specifying ColumnFamily
1174    pub fn get_pinned_cf_opt<K: AsRef<[u8]>>(
1175        &'_ self,
1176        cf: &impl AsColumnFamilyRef,
1177        key: K,
1178        readopts: &ReadOptions,
1179    ) -> Result<Option<DBPinnableSlice<'_>>, Error> {
1180        if readopts.inner.is_null() {
1181            return Err(Error::new(
1182                "Unable to create RocksDB read options. This is a fairly trivial call, and its \
1183                 failure may be indicative of a mis-compiled or mis-loaded RocksDB library."
1184                    .to_owned(),
1185            ));
1186        }
1187
1188        let key = key.as_ref();
1189        unsafe {
1190            let val = ffi_try!(ffi::rocksdb_get_pinned_cf(
1191                self.inner.inner(),
1192                readopts.inner,
1193                cf.inner(),
1194                key.as_ptr() as *const c_char,
1195                key.len() as size_t,
1196            ));
1197            if val.is_null() {
1198                Ok(None)
1199            } else {
1200                Ok(Some(DBPinnableSlice::from_c(val)))
1201            }
1202        }
1203    }
1204
1205    /// Return the value associated with a key using RocksDB's PinnableSlice
1206    /// so as to avoid unnecessary memory copy. Similar to get_pinned_cf_opt but
1207    /// leverages default options.
1208    pub fn get_pinned_cf<K: AsRef<[u8]>>(
1209        &'_ self,
1210        cf: &impl AsColumnFamilyRef,
1211        key: K,
1212    ) -> Result<Option<DBPinnableSlice<'_>>, Error> {
1213        DEFAULT_READ_OPTS.with(|opts| self.get_pinned_cf_opt(cf, key, opts))
1214    }
1215
1216    /// Return the values associated with the given keys.
1217    pub fn multi_get<K, I>(&self, keys: I) -> Vec<Result<Option<Vec<u8>>, Error>>
1218    where
1219        K: AsRef<[u8]>,
1220        I: IntoIterator<Item = K>,
1221    {
1222        DEFAULT_READ_OPTS.with(|opts| self.multi_get_opt(keys, opts))
1223    }
1224
1225    /// Return the values associated with the given keys using read options.
1226    pub fn multi_get_opt<K, I>(
1227        &self,
1228        keys: I,
1229        readopts: &ReadOptions,
1230    ) -> Vec<Result<Option<Vec<u8>>, Error>>
1231    where
1232        K: AsRef<[u8]>,
1233        I: IntoIterator<Item = K>,
1234    {
1235        let owned_keys: Vec<K> = keys.into_iter().collect();
1236        let keys_sizes: Vec<usize> = owned_keys.iter().map(|k| k.as_ref().len()).collect();
1237        let ptr_keys: Vec<*const c_char> = owned_keys
1238            .iter()
1239            .map(|k| k.as_ref().as_ptr() as *const c_char)
1240            .collect();
1241
1242        let mut values: Vec<*mut c_char> = Vec::with_capacity(ptr_keys.len());
1243        let mut values_sizes: Vec<usize> = Vec::with_capacity(ptr_keys.len());
1244        let mut errors: Vec<*mut c_char> = Vec::with_capacity(ptr_keys.len());
1245        unsafe {
1246            ffi::rocksdb_multi_get(
1247                self.inner.inner(),
1248                readopts.inner,
1249                ptr_keys.len(),
1250                ptr_keys.as_ptr(),
1251                keys_sizes.as_ptr(),
1252                values.as_mut_ptr(),
1253                values_sizes.as_mut_ptr(),
1254                errors.as_mut_ptr(),
1255            );
1256        }
1257
1258        unsafe {
1259            values.set_len(ptr_keys.len());
1260            values_sizes.set_len(ptr_keys.len());
1261            errors.set_len(ptr_keys.len());
1262        }
1263
1264        convert_values(values, values_sizes, errors)
1265    }
1266
1267    /// Returns pinned values associated with the given keys using default read options.
1268    ///
1269    /// This iterates `get_pinned_opt` for each key and returns zero-copy
1270    /// `DBPinnableSlice` values when present, avoiding value copies.
1271    pub fn multi_get_pinned<K, I>(
1272        &'_ self,
1273        keys: I,
1274    ) -> Vec<Result<Option<DBPinnableSlice<'_>>, Error>>
1275    where
1276        K: AsRef<[u8]>,
1277        I: IntoIterator<Item = K>,
1278    {
1279        DEFAULT_READ_OPTS.with(|opts| self.multi_get_pinned_opt(keys, opts))
1280    }
1281
1282    /// Returns pinned values associated with the given keys using the provided read options.
1283    ///
1284    /// This iterates `get_pinned_opt` for each key and returns zero-copy
1285    /// `DBPinnableSlice` values when present, avoiding value copies.
1286    pub fn multi_get_pinned_opt<K, I>(
1287        &'_ self,
1288        keys: I,
1289        readopts: &ReadOptions,
1290    ) -> Vec<Result<Option<DBPinnableSlice<'_>>, Error>>
1291    where
1292        K: AsRef<[u8]>,
1293        I: IntoIterator<Item = K>,
1294    {
1295        keys.into_iter()
1296            .map(|k| self.get_pinned_opt(k, readopts))
1297            .collect()
1298    }
1299
1300    /// Returns pinned values associated with the given keys and column families
1301    /// using default read options.
1302    pub fn multi_get_pinned_cf<'a, 'b: 'a, K, I, W>(
1303        &'a self,
1304        keys: I,
1305    ) -> Vec<Result<Option<DBPinnableSlice<'a>>, Error>>
1306    where
1307        K: AsRef<[u8]>,
1308        I: IntoIterator<Item = (&'b W, K)>,
1309        W: 'b + AsColumnFamilyRef,
1310    {
1311        DEFAULT_READ_OPTS.with(|opts| self.multi_get_pinned_cf_opt(keys, opts))
1312    }
1313
1314    /// Returns pinned values associated with the given keys and column families
1315    /// using the provided read options.
1316    pub fn multi_get_pinned_cf_opt<'a, 'b: 'a, K, I, W>(
1317        &'a self,
1318        keys: I,
1319        readopts: &ReadOptions,
1320    ) -> Vec<Result<Option<DBPinnableSlice<'a>>, Error>>
1321    where
1322        K: AsRef<[u8]>,
1323        I: IntoIterator<Item = (&'b W, K)>,
1324        W: 'b + AsColumnFamilyRef,
1325    {
1326        keys.into_iter()
1327            .map(|(cf, k)| self.get_pinned_cf_opt(cf, k, readopts))
1328            .collect()
1329    }
1330
1331    /// Return the values associated with the given keys and column families.
1332    pub fn multi_get_cf<'a, 'b: 'a, K, I, W>(
1333        &'a self,
1334        keys: I,
1335    ) -> Vec<Result<Option<Vec<u8>>, Error>>
1336    where
1337        K: AsRef<[u8]>,
1338        I: IntoIterator<Item = (&'b W, K)>,
1339        W: 'b + AsColumnFamilyRef,
1340    {
1341        DEFAULT_READ_OPTS.with(|opts| self.multi_get_cf_opt(keys, opts))
1342    }
1343
1344    /// Return the values associated with the given keys and column families using read options.
1345    pub fn multi_get_cf_opt<'a, 'b: 'a, K, I, W>(
1346        &'a self,
1347        keys: I,
1348        readopts: &ReadOptions,
1349    ) -> Vec<Result<Option<Vec<u8>>, Error>>
1350    where
1351        K: AsRef<[u8]>,
1352        I: IntoIterator<Item = (&'b W, K)>,
1353        W: 'b + AsColumnFamilyRef,
1354    {
1355        let cfs_and_owned_keys: Vec<(&'b W, K)> = keys.into_iter().collect();
1356        let keys_sizes: Vec<usize> = cfs_and_owned_keys
1357            .iter()
1358            .map(|(_, k)| k.as_ref().len())
1359            .collect();
1360        let ptr_keys: Vec<*const c_char> = cfs_and_owned_keys
1361            .iter()
1362            .map(|(_, k)| k.as_ref().as_ptr() as *const c_char)
1363            .collect();
1364        let ptr_cfs: Vec<*const ffi::rocksdb_column_family_handle_t> = cfs_and_owned_keys
1365            .iter()
1366            .map(|(c, _)| c.inner().cast_const())
1367            .collect();
1368        let mut values: Vec<*mut c_char> = Vec::with_capacity(ptr_keys.len());
1369        let mut values_sizes: Vec<usize> = Vec::with_capacity(ptr_keys.len());
1370        let mut errors: Vec<*mut c_char> = Vec::with_capacity(ptr_keys.len());
1371        unsafe {
1372            ffi::rocksdb_multi_get_cf(
1373                self.inner.inner(),
1374                readopts.inner,
1375                ptr_cfs.as_ptr(),
1376                ptr_keys.len(),
1377                ptr_keys.as_ptr(),
1378                keys_sizes.as_ptr(),
1379                values.as_mut_ptr(),
1380                values_sizes.as_mut_ptr(),
1381                errors.as_mut_ptr(),
1382            );
1383        }
1384
1385        unsafe {
1386            values.set_len(ptr_keys.len());
1387            values_sizes.set_len(ptr_keys.len());
1388            errors.set_len(ptr_keys.len());
1389        }
1390
1391        convert_values(values, values_sizes, errors)
1392    }
1393
1394    /// Return the values associated with the given keys and the specified column family
1395    /// where internally the read requests are processed in batch if block-based table
1396    /// SST format is used.  It is a more optimized version of multi_get_cf.
1397    pub fn batched_multi_get_cf<'a, K, I>(
1398        &'_ self,
1399        cf: &impl AsColumnFamilyRef,
1400        keys: I,
1401        sorted_input: bool,
1402    ) -> Vec<Result<Option<DBPinnableSlice<'_>>, Error>>
1403    where
1404        K: AsRef<[u8]> + 'a + ?Sized,
1405        I: IntoIterator<Item = &'a K>,
1406    {
1407        DEFAULT_READ_OPTS.with(|opts| self.batched_multi_get_cf_opt(cf, keys, sorted_input, opts))
1408    }
1409
1410    /// Return the values associated with the given keys and the specified column family
1411    /// where internally the read requests are processed in batch if block-based table
1412    /// SST format is used. It is a more optimized version of multi_get_cf_opt.
1413    pub fn batched_multi_get_cf_opt<'a, K, I>(
1414        &'_ self,
1415        cf: &impl AsColumnFamilyRef,
1416        keys: I,
1417        sorted_input: bool,
1418        readopts: &ReadOptions,
1419    ) -> Vec<Result<Option<DBPinnableSlice<'_>>, Error>>
1420    where
1421        K: AsRef<[u8]> + 'a + ?Sized,
1422        I: IntoIterator<Item = &'a K>,
1423    {
1424        let (ptr_keys, keys_sizes): (Vec<_>, Vec<_>) = keys
1425            .into_iter()
1426            .map(|k| {
1427                let k = k.as_ref();
1428                (k.as_ptr() as *const c_char, k.len())
1429            })
1430            .unzip();
1431
1432        let mut pinned_values = vec![ptr::null_mut(); ptr_keys.len()];
1433        let mut errors = vec![ptr::null_mut(); ptr_keys.len()];
1434
1435        unsafe {
1436            ffi::rocksdb_batched_multi_get_cf(
1437                self.inner.inner(),
1438                readopts.inner,
1439                cf.inner(),
1440                ptr_keys.len(),
1441                ptr_keys.as_ptr(),
1442                keys_sizes.as_ptr(),
1443                pinned_values.as_mut_ptr(),
1444                errors.as_mut_ptr(),
1445                sorted_input,
1446            );
1447            pinned_values
1448                .into_iter()
1449                .zip(errors)
1450                .map(|(v, e)| {
1451                    if e.is_null() {
1452                        if v.is_null() {
1453                            Ok(None)
1454                        } else {
1455                            Ok(Some(DBPinnableSlice::from_c(v)))
1456                        }
1457                    } else {
1458                        Err(convert_rocksdb_error(e))
1459                    }
1460                })
1461                .collect()
1462        }
1463    }
1464
1465    /// Returns `false` if the given key definitely doesn't exist in the database, otherwise returns
1466    /// `true`. This function uses default `ReadOptions`.
1467    pub fn key_may_exist<K: AsRef<[u8]>>(&self, key: K) -> bool {
1468        DEFAULT_READ_OPTS.with(|opts| self.key_may_exist_opt(key, opts))
1469    }
1470
1471    /// Returns `false` if the given key definitely doesn't exist in the database, otherwise returns
1472    /// `true`.
1473    pub fn key_may_exist_opt<K: AsRef<[u8]>>(&self, key: K, readopts: &ReadOptions) -> bool {
1474        let key = key.as_ref();
1475        unsafe {
1476            0 != ffi::rocksdb_key_may_exist(
1477                self.inner.inner(),
1478                readopts.inner,
1479                key.as_ptr() as *const c_char,
1480                key.len() as size_t,
1481                ptr::null_mut(), /*value*/
1482                ptr::null_mut(), /*val_len*/
1483                ptr::null(),     /*timestamp*/
1484                0,               /*timestamp_len*/
1485                ptr::null_mut(), /*value_found*/
1486            )
1487        }
1488    }
1489
1490    /// Returns `false` if the given key definitely doesn't exist in the specified column family,
1491    /// otherwise returns `true`. This function uses default `ReadOptions`.
1492    pub fn key_may_exist_cf<K: AsRef<[u8]>>(&self, cf: &impl AsColumnFamilyRef, key: K) -> bool {
1493        DEFAULT_READ_OPTS.with(|opts| self.key_may_exist_cf_opt(cf, key, opts))
1494    }
1495
1496    /// Returns `false` if the given key definitely doesn't exist in the specified column family,
1497    /// otherwise returns `true`.
1498    pub fn key_may_exist_cf_opt<K: AsRef<[u8]>>(
1499        &self,
1500        cf: &impl AsColumnFamilyRef,
1501        key: K,
1502        readopts: &ReadOptions,
1503    ) -> bool {
1504        let key = key.as_ref();
1505        0 != unsafe {
1506            ffi::rocksdb_key_may_exist_cf(
1507                self.inner.inner(),
1508                readopts.inner,
1509                cf.inner(),
1510                key.as_ptr() as *const c_char,
1511                key.len() as size_t,
1512                ptr::null_mut(), /*value*/
1513                ptr::null_mut(), /*val_len*/
1514                ptr::null(),     /*timestamp*/
1515                0,               /*timestamp_len*/
1516                ptr::null_mut(), /*value_found*/
1517            )
1518        }
1519    }
1520
1521    /// If the key definitely does not exist in the database, then this method
1522    /// returns `(false, None)`, else `(true, None)` if it may.
1523    /// If the key is found in memory, then it returns `(true, Some<CSlice>)`.
1524    ///
1525    /// This check is potentially lighter-weight than calling `get()`. One way
1526    /// to make this lighter weight is to avoid doing any IOs.
1527    pub fn key_may_exist_cf_opt_value<K: AsRef<[u8]>>(
1528        &self,
1529        cf: &impl AsColumnFamilyRef,
1530        key: K,
1531        readopts: &ReadOptions,
1532    ) -> (bool, Option<CSlice>) {
1533        let key = key.as_ref();
1534        let mut val: *mut c_char = ptr::null_mut();
1535        let mut val_len: usize = 0;
1536        let mut value_found: c_uchar = 0;
1537        let may_exists = 0
1538            != unsafe {
1539                ffi::rocksdb_key_may_exist_cf(
1540                    self.inner.inner(),
1541                    readopts.inner,
1542                    cf.inner(),
1543                    key.as_ptr() as *const c_char,
1544                    key.len() as size_t,
1545                    &raw mut val,         /*value*/
1546                    &raw mut val_len,     /*val_len*/
1547                    ptr::null(),          /*timestamp*/
1548                    0,                    /*timestamp_len*/
1549                    &raw mut value_found, /*value_found*/
1550                )
1551            };
1552        // The value is only allocated (using malloc) and returned if it is found and
1553        // value_found isn't NULL. In that case the user is responsible for freeing it.
1554        if may_exists && value_found != 0 {
1555            (
1556                may_exists,
1557                Some(unsafe { CSlice::from_raw_parts(val, val_len) }),
1558            )
1559        } else {
1560            (may_exists, None)
1561        }
1562    }
1563
1564    fn create_inner_cf_handle(
1565        &self,
1566        name: impl CStrLike,
1567        opts: &Options,
1568    ) -> Result<*mut ffi::rocksdb_column_family_handle_t, Error> {
1569        let cf_name = name.bake().map_err(|err| {
1570            Error::new(format!(
1571                "Failed to convert path to CString when creating cf: {err}"
1572            ))
1573        })?;
1574
1575        // Can't use ffi_try: rocksdb_create_column_family has a bug where it allocates a
1576        // result that needs to be freed on error
1577        let mut err: *mut ::libc::c_char = ::std::ptr::null_mut();
1578        let cf_handle = unsafe {
1579            ffi::rocksdb_create_column_family(
1580                self.inner.inner(),
1581                opts.inner,
1582                cf_name.as_ptr(),
1583                &raw mut err,
1584            )
1585        };
1586        if !err.is_null() {
1587            if !cf_handle.is_null() {
1588                unsafe { ffi::rocksdb_column_family_handle_destroy(cf_handle) };
1589            }
1590            return Err(convert_rocksdb_error(err));
1591        }
1592        Ok(cf_handle)
1593    }
1594
1595    pub fn iterator<'a: 'b, 'b>(
1596        &'a self,
1597        mode: IteratorMode,
1598    ) -> DBIteratorWithThreadMode<'b, Self> {
1599        let readopts = ReadOptions::default();
1600        self.iterator_opt(mode, readopts)
1601    }
1602
1603    pub fn iterator_opt<'a: 'b, 'b>(
1604        &'a self,
1605        mode: IteratorMode,
1606        readopts: ReadOptions,
1607    ) -> DBIteratorWithThreadMode<'b, Self> {
1608        DBIteratorWithThreadMode::new(self, readopts, mode)
1609    }
1610
1611    /// Opens an iterator using the provided ReadOptions.
1612    /// This is used when you want to iterate over a specific ColumnFamily with a modified ReadOptions
1613    pub fn iterator_cf_opt<'a: 'b, 'b>(
1614        &'a self,
1615        cf_handle: &impl AsColumnFamilyRef,
1616        readopts: ReadOptions,
1617        mode: IteratorMode,
1618    ) -> DBIteratorWithThreadMode<'b, Self> {
1619        DBIteratorWithThreadMode::new_cf(self, cf_handle.inner(), readopts, mode)
1620    }
1621
1622    /// Opens an iterator with `set_total_order_seek` enabled.
1623    /// This must be used to iterate across prefixes when `set_memtable_factory` has been called
1624    /// with a Hash-based implementation.
1625    pub fn full_iterator<'a: 'b, 'b>(
1626        &'a self,
1627        mode: IteratorMode,
1628    ) -> DBIteratorWithThreadMode<'b, Self> {
1629        let mut opts = ReadOptions::default();
1630        opts.set_total_order_seek(true);
1631        DBIteratorWithThreadMode::new(self, opts, mode)
1632    }
1633
1634    pub fn prefix_iterator<'a: 'b, 'b, P: AsRef<[u8]>>(
1635        &'a self,
1636        prefix: P,
1637    ) -> DBIteratorWithThreadMode<'b, Self> {
1638        let mut opts = ReadOptions::default();
1639        opts.set_prefix_same_as_start(true);
1640        DBIteratorWithThreadMode::new(
1641            self,
1642            opts,
1643            IteratorMode::From(prefix.as_ref(), Direction::Forward),
1644        )
1645    }
1646
1647    pub fn iterator_cf<'a: 'b, 'b>(
1648        &'a self,
1649        cf_handle: &impl AsColumnFamilyRef,
1650        mode: IteratorMode,
1651    ) -> DBIteratorWithThreadMode<'b, Self> {
1652        let opts = ReadOptions::default();
1653        DBIteratorWithThreadMode::new_cf(self, cf_handle.inner(), opts, mode)
1654    }
1655
1656    pub fn full_iterator_cf<'a: 'b, 'b>(
1657        &'a self,
1658        cf_handle: &impl AsColumnFamilyRef,
1659        mode: IteratorMode,
1660    ) -> DBIteratorWithThreadMode<'b, Self> {
1661        let mut opts = ReadOptions::default();
1662        opts.set_total_order_seek(true);
1663        DBIteratorWithThreadMode::new_cf(self, cf_handle.inner(), opts, mode)
1664    }
1665
1666    pub fn prefix_iterator_cf<'a, P: AsRef<[u8]>>(
1667        &'a self,
1668        cf_handle: &impl AsColumnFamilyRef,
1669        prefix: P,
1670    ) -> DBIteratorWithThreadMode<'a, Self> {
1671        let mut opts = ReadOptions::default();
1672        opts.set_prefix_same_as_start(true);
1673        DBIteratorWithThreadMode::<'a, Self>::new_cf(
1674            self,
1675            cf_handle.inner(),
1676            opts,
1677            IteratorMode::From(prefix.as_ref(), Direction::Forward),
1678        )
1679    }
1680
1681    /// Returns `true` if there exists at least one key with the given prefix
1682    /// in the default column family using default read options.
1683    ///
1684    /// When to use: prefer this for one-shot checks. It enables
1685    /// `prefix_same_as_start(true)` and bounds the iterator to the
1686    /// prefix via `PrefixRange`, minimizing stray IO per call.
1687    pub fn prefix_exists<P: AsRef<[u8]>>(&self, prefix: P) -> Result<bool, Error> {
1688        let p = prefix.as_ref();
1689        PREFIX_READ_OPTS.with(|rc| {
1690            let mut opts = rc.borrow_mut();
1691            opts.set_iterate_range(crate::PrefixRange(p));
1692            self.prefix_exists_opt(p, &opts)
1693        })
1694    }
1695
1696    /// Returns `true` if there exists at least one key with the given prefix
1697    /// in the default column family using the provided read options.
1698    pub fn prefix_exists_opt<P: AsRef<[u8]>>(
1699        &self,
1700        prefix: P,
1701        readopts: &ReadOptions,
1702    ) -> Result<bool, Error> {
1703        let prefix = prefix.as_ref();
1704        let iter = unsafe { self.create_iterator(readopts) };
1705        let res = unsafe {
1706            ffi::rocksdb_iter_seek(
1707                iter,
1708                prefix.as_ptr() as *const c_char,
1709                prefix.len() as size_t,
1710            );
1711            if ffi::rocksdb_iter_valid(iter) != 0 {
1712                let mut key_len: size_t = 0;
1713                let key_ptr = ffi::rocksdb_iter_key(iter, &raw mut key_len);
1714                let key = slice::from_raw_parts(key_ptr as *const u8, key_len as usize);
1715                Ok(key.starts_with(prefix))
1716            } else if let Err(e) = (|| {
1717                // Check status to differentiate end-of-range vs error
1718                ffi_try!(ffi::rocksdb_iter_get_error(iter));
1719                Ok::<(), Error>(())
1720            })() {
1721                Err(e)
1722            } else {
1723                Ok(false)
1724            }
1725        };
1726        unsafe { ffi::rocksdb_iter_destroy(iter) };
1727        res
1728    }
1729
1730    /// Creates a reusable prefix prober over the default column family using
1731    /// read options optimized for prefix probes.
1732    ///
1733    /// When to use: prefer this in hot loops with many checks per second. It
1734    /// reuses a raw iterator to avoid per-call allocation/FFI overhead. If you
1735    /// need custom tuning (e.g. async IO, readahead, cache-only), use
1736    /// `prefix_prober_with_opts`.
1737    pub fn prefix_prober(&self) -> PrefixProber<'_, Self> {
1738        let mut opts = ReadOptions::default();
1739        opts.set_prefix_same_as_start(true);
1740        PrefixProber {
1741            raw: DBRawIteratorWithThreadMode::new(self, opts),
1742        }
1743    }
1744
1745    /// Creates a reusable prefix prober over the default column family using
1746    /// the provided read options (owned).
1747    ///
1748    /// When to use: advanced tuning for heavy workloads. Callers can set
1749    /// `set_async_io(true)`, `set_readahead_size`, `set_read_tier`, etc. Note:
1750    /// the prober owns `ReadOptions` to keep internal buffers alive.
1751    pub fn prefix_prober_with_opts(&self, readopts: ReadOptions) -> PrefixProber<'_, Self> {
1752        PrefixProber {
1753            raw: DBRawIteratorWithThreadMode::new(self, readopts),
1754        }
1755    }
1756
1757    /// Creates a reusable prefix prober over the specified column family using
1758    /// read options optimized for prefix probes.
1759    pub fn prefix_prober_cf(&self, cf_handle: &impl AsColumnFamilyRef) -> PrefixProber<'_, Self> {
1760        let mut opts = ReadOptions::default();
1761        opts.set_prefix_same_as_start(true);
1762        PrefixProber {
1763            raw: DBRawIteratorWithThreadMode::new_cf(self, cf_handle.inner(), opts),
1764        }
1765    }
1766
1767    /// Creates a reusable prefix prober over the specified column family using
1768    /// the provided read options (owned).
1769    ///
1770    /// When to use: advanced tuning for heavy workloads on a specific CF.
1771    pub fn prefix_prober_cf_with_opts(
1772        &self,
1773        cf_handle: &impl AsColumnFamilyRef,
1774        readopts: ReadOptions,
1775    ) -> PrefixProber<'_, Self> {
1776        PrefixProber {
1777            raw: DBRawIteratorWithThreadMode::new_cf(self, cf_handle.inner(), readopts),
1778        }
1779    }
1780
1781    /// Returns `true` if there exists at least one key with the given prefix
1782    /// in the specified column family using default read options.
1783    ///
1784    /// When to use: one-shot checks on a CF. Enables
1785    /// `prefix_same_as_start(true)` and bounds the iterator via `PrefixRange`.
1786    pub fn prefix_exists_cf<P: AsRef<[u8]>>(
1787        &self,
1788        cf_handle: &impl AsColumnFamilyRef,
1789        prefix: P,
1790    ) -> Result<bool, Error> {
1791        let p = prefix.as_ref();
1792        PREFIX_READ_OPTS.with(|rc| {
1793            let mut opts = rc.borrow_mut();
1794            opts.set_iterate_range(crate::PrefixRange(p));
1795            self.prefix_exists_cf_opt(cf_handle, p, &opts)
1796        })
1797    }
1798
1799    /// Returns `true` if there exists at least one key with the given prefix
1800    /// in the specified column family using the provided read options.
1801    pub fn prefix_exists_cf_opt<P: AsRef<[u8]>>(
1802        &self,
1803        cf_handle: &impl AsColumnFamilyRef,
1804        prefix: P,
1805        readopts: &ReadOptions,
1806    ) -> Result<bool, Error> {
1807        let prefix = prefix.as_ref();
1808        let iter = unsafe { self.create_iterator_cf(cf_handle.inner(), readopts) };
1809        let res = unsafe {
1810            ffi::rocksdb_iter_seek(
1811                iter,
1812                prefix.as_ptr() as *const c_char,
1813                prefix.len() as size_t,
1814            );
1815            if ffi::rocksdb_iter_valid(iter) != 0 {
1816                let mut key_len: size_t = 0;
1817                let key_ptr = ffi::rocksdb_iter_key(iter, &raw mut key_len);
1818                let key = slice::from_raw_parts(key_ptr as *const u8, key_len as usize);
1819                Ok(key.starts_with(prefix))
1820            } else if let Err(e) = (|| {
1821                ffi_try!(ffi::rocksdb_iter_get_error(iter));
1822                Ok::<(), Error>(())
1823            })() {
1824                Err(e)
1825            } else {
1826                Ok(false)
1827            }
1828        };
1829        unsafe { ffi::rocksdb_iter_destroy(iter) };
1830        res
1831    }
1832
1833    /// Opens a raw iterator over the database, using the default read options
1834    pub fn raw_iterator<'a: 'b, 'b>(&'a self) -> DBRawIteratorWithThreadMode<'b, Self> {
1835        let opts = ReadOptions::default();
1836        DBRawIteratorWithThreadMode::new(self, opts)
1837    }
1838
1839    /// Opens a raw iterator over the given column family, using the default read options
1840    pub fn raw_iterator_cf<'a: 'b, 'b>(
1841        &'a self,
1842        cf_handle: &impl AsColumnFamilyRef,
1843    ) -> DBRawIteratorWithThreadMode<'b, Self> {
1844        let opts = ReadOptions::default();
1845        DBRawIteratorWithThreadMode::new_cf(self, cf_handle.inner(), opts)
1846    }
1847
1848    /// Opens a raw iterator over the database, using the given read options
1849    pub fn raw_iterator_opt<'a: 'b, 'b>(
1850        &'a self,
1851        readopts: ReadOptions,
1852    ) -> DBRawIteratorWithThreadMode<'b, Self> {
1853        DBRawIteratorWithThreadMode::new(self, readopts)
1854    }
1855
1856    /// Opens a raw iterator over the given column family, using the given read options
1857    pub fn raw_iterator_cf_opt<'a: 'b, 'b>(
1858        &'a self,
1859        cf_handle: &impl AsColumnFamilyRef,
1860        readopts: ReadOptions,
1861    ) -> DBRawIteratorWithThreadMode<'b, Self> {
1862        DBRawIteratorWithThreadMode::new_cf(self, cf_handle.inner(), readopts)
1863    }
1864
1865    pub fn snapshot(&'_ self) -> SnapshotWithThreadMode<'_, Self> {
1866        SnapshotWithThreadMode::<Self>::new(self)
1867    }
1868
1869    pub fn put_opt<K, V>(&self, key: K, value: V, writeopts: &WriteOptions) -> Result<(), Error>
1870    where
1871        K: AsRef<[u8]>,
1872        V: AsRef<[u8]>,
1873    {
1874        let key = key.as_ref();
1875        let value = value.as_ref();
1876
1877        unsafe {
1878            ffi_try!(ffi::rocksdb_put(
1879                self.inner.inner(),
1880                writeopts.inner,
1881                key.as_ptr() as *const c_char,
1882                key.len() as size_t,
1883                value.as_ptr() as *const c_char,
1884                value.len() as size_t,
1885            ));
1886            Ok(())
1887        }
1888    }
1889
1890    pub fn put_cf_opt<K, V>(
1891        &self,
1892        cf: &impl AsColumnFamilyRef,
1893        key: K,
1894        value: V,
1895        writeopts: &WriteOptions,
1896    ) -> Result<(), Error>
1897    where
1898        K: AsRef<[u8]>,
1899        V: AsRef<[u8]>,
1900    {
1901        let key = key.as_ref();
1902        let value = value.as_ref();
1903
1904        unsafe {
1905            ffi_try!(ffi::rocksdb_put_cf(
1906                self.inner.inner(),
1907                writeopts.inner,
1908                cf.inner(),
1909                key.as_ptr() as *const c_char,
1910                key.len() as size_t,
1911                value.as_ptr() as *const c_char,
1912                value.len() as size_t,
1913            ));
1914            Ok(())
1915        }
1916    }
1917
1918    /// Set the database entry for "key" to "value" with WriteOptions.
1919    /// If "key" already exists, it will coexist with previous entry.
1920    /// `Get` with a timestamp ts specified in ReadOptions will return
1921    /// the most recent key/value whose timestamp is smaller than or equal to ts.
1922    /// Takes an additional argument `ts` as the timestamp.
1923    /// Note: the DB must be opened with user defined timestamp enabled.
1924    pub fn put_with_ts_opt<K, V, S>(
1925        &self,
1926        key: K,
1927        ts: S,
1928        value: V,
1929        writeopts: &WriteOptions,
1930    ) -> Result<(), Error>
1931    where
1932        K: AsRef<[u8]>,
1933        V: AsRef<[u8]>,
1934        S: AsRef<[u8]>,
1935    {
1936        let key = key.as_ref();
1937        let value = value.as_ref();
1938        let ts = ts.as_ref();
1939        unsafe {
1940            ffi_try!(ffi::rocksdb_put_with_ts(
1941                self.inner.inner(),
1942                writeopts.inner,
1943                key.as_ptr() as *const c_char,
1944                key.len() as size_t,
1945                ts.as_ptr() as *const c_char,
1946                ts.len() as size_t,
1947                value.as_ptr() as *const c_char,
1948                value.len() as size_t,
1949            ));
1950            Ok(())
1951        }
1952    }
1953
1954    /// Put with timestamp in a specific column family with WriteOptions.
1955    /// If "key" already exists, it will coexist with previous entry.
1956    /// `Get` with a timestamp ts specified in ReadOptions will return
1957    /// the most recent key/value whose timestamp is smaller than or equal to ts.
1958    /// Takes an additional argument `ts` as the timestamp.
1959    /// Note: the DB must be opened with user defined timestamp enabled.
1960    pub fn put_cf_with_ts_opt<K, V, S>(
1961        &self,
1962        cf: &impl AsColumnFamilyRef,
1963        key: K,
1964        ts: S,
1965        value: V,
1966        writeopts: &WriteOptions,
1967    ) -> Result<(), Error>
1968    where
1969        K: AsRef<[u8]>,
1970        V: AsRef<[u8]>,
1971        S: AsRef<[u8]>,
1972    {
1973        let key = key.as_ref();
1974        let value = value.as_ref();
1975        let ts = ts.as_ref();
1976        unsafe {
1977            ffi_try!(ffi::rocksdb_put_cf_with_ts(
1978                self.inner.inner(),
1979                writeopts.inner,
1980                cf.inner(),
1981                key.as_ptr() as *const c_char,
1982                key.len() as size_t,
1983                ts.as_ptr() as *const c_char,
1984                ts.len() as size_t,
1985                value.as_ptr() as *const c_char,
1986                value.len() as size_t,
1987            ));
1988            Ok(())
1989        }
1990    }
1991
1992    pub fn merge_opt<K, V>(&self, key: K, value: V, writeopts: &WriteOptions) -> Result<(), Error>
1993    where
1994        K: AsRef<[u8]>,
1995        V: AsRef<[u8]>,
1996    {
1997        let key = key.as_ref();
1998        let value = value.as_ref();
1999
2000        unsafe {
2001            ffi_try!(ffi::rocksdb_merge(
2002                self.inner.inner(),
2003                writeopts.inner,
2004                key.as_ptr() as *const c_char,
2005                key.len() as size_t,
2006                value.as_ptr() as *const c_char,
2007                value.len() as size_t,
2008            ));
2009            Ok(())
2010        }
2011    }
2012
2013    pub fn merge_cf_opt<K, V>(
2014        &self,
2015        cf: &impl AsColumnFamilyRef,
2016        key: K,
2017        value: V,
2018        writeopts: &WriteOptions,
2019    ) -> Result<(), Error>
2020    where
2021        K: AsRef<[u8]>,
2022        V: AsRef<[u8]>,
2023    {
2024        let key = key.as_ref();
2025        let value = value.as_ref();
2026
2027        unsafe {
2028            ffi_try!(ffi::rocksdb_merge_cf(
2029                self.inner.inner(),
2030                writeopts.inner,
2031                cf.inner(),
2032                key.as_ptr() as *const c_char,
2033                key.len() as size_t,
2034                value.as_ptr() as *const c_char,
2035                value.len() as size_t,
2036            ));
2037            Ok(())
2038        }
2039    }
2040
2041    pub fn delete_opt<K: AsRef<[u8]>>(
2042        &self,
2043        key: K,
2044        writeopts: &WriteOptions,
2045    ) -> Result<(), Error> {
2046        let key = key.as_ref();
2047
2048        unsafe {
2049            ffi_try!(ffi::rocksdb_delete(
2050                self.inner.inner(),
2051                writeopts.inner,
2052                key.as_ptr() as *const c_char,
2053                key.len() as size_t,
2054            ));
2055            Ok(())
2056        }
2057    }
2058
2059    pub fn delete_cf_opt<K: AsRef<[u8]>>(
2060        &self,
2061        cf: &impl AsColumnFamilyRef,
2062        key: K,
2063        writeopts: &WriteOptions,
2064    ) -> Result<(), Error> {
2065        let key = key.as_ref();
2066
2067        unsafe {
2068            ffi_try!(ffi::rocksdb_delete_cf(
2069                self.inner.inner(),
2070                writeopts.inner,
2071                cf.inner(),
2072                key.as_ptr() as *const c_char,
2073                key.len() as size_t,
2074            ));
2075            Ok(())
2076        }
2077    }
2078
2079    /// Remove the database entry (if any) for "key" with WriteOptions.
2080    /// Takes an additional argument `ts` as the timestamp.
2081    /// Note: the DB must be opened with user defined timestamp enabled.
2082    pub fn delete_with_ts_opt<K, S>(
2083        &self,
2084        key: K,
2085        ts: S,
2086        writeopts: &WriteOptions,
2087    ) -> Result<(), Error>
2088    where
2089        K: AsRef<[u8]>,
2090        S: AsRef<[u8]>,
2091    {
2092        let key = key.as_ref();
2093        let ts = ts.as_ref();
2094        unsafe {
2095            ffi_try!(ffi::rocksdb_delete_with_ts(
2096                self.inner.inner(),
2097                writeopts.inner,
2098                key.as_ptr() as *const c_char,
2099                key.len() as size_t,
2100                ts.as_ptr() as *const c_char,
2101                ts.len() as size_t,
2102            ));
2103            Ok(())
2104        }
2105    }
2106
2107    /// Delete with timestamp in a specific column family with WriteOptions.
2108    /// Takes an additional argument `ts` as the timestamp.
2109    /// Note: the DB must be opened with user defined timestamp enabled.
2110    pub fn delete_cf_with_ts_opt<K, S>(
2111        &self,
2112        cf: &impl AsColumnFamilyRef,
2113        key: K,
2114        ts: S,
2115        writeopts: &WriteOptions,
2116    ) -> Result<(), Error>
2117    where
2118        K: AsRef<[u8]>,
2119        S: AsRef<[u8]>,
2120    {
2121        let key = key.as_ref();
2122        let ts = ts.as_ref();
2123        unsafe {
2124            ffi_try!(ffi::rocksdb_delete_cf_with_ts(
2125                self.inner.inner(),
2126                writeopts.inner,
2127                cf.inner(),
2128                key.as_ptr() as *const c_char,
2129                key.len() as size_t,
2130                ts.as_ptr() as *const c_char,
2131                ts.len() as size_t,
2132            ));
2133            Ok(())
2134        }
2135    }
2136
2137    pub fn put<K, V>(&self, key: K, value: V) -> Result<(), Error>
2138    where
2139        K: AsRef<[u8]>,
2140        V: AsRef<[u8]>,
2141    {
2142        DEFAULT_WRITE_OPTS.with(|opts| self.put_opt(key, value, opts))
2143    }
2144
2145    pub fn put_cf<K, V>(&self, cf: &impl AsColumnFamilyRef, key: K, value: V) -> Result<(), Error>
2146    where
2147        K: AsRef<[u8]>,
2148        V: AsRef<[u8]>,
2149    {
2150        DEFAULT_WRITE_OPTS.with(|opts| self.put_cf_opt(cf, key, value, opts))
2151    }
2152
2153    /// Set the database entry for "key" to "value".
2154    /// If "key" already exists, it will coexist with previous entry.
2155    /// `Get` with a timestamp ts specified in ReadOptions will return
2156    /// the most recent key/value whose timestamp is smaller than or equal to ts.
2157    /// Takes an additional argument `ts` as the timestamp.
2158    /// Note: the DB must be opened with user defined timestamp enabled.
2159    pub fn put_with_ts<K, V, S>(&self, key: K, ts: S, value: V) -> Result<(), Error>
2160    where
2161        K: AsRef<[u8]>,
2162        V: AsRef<[u8]>,
2163        S: AsRef<[u8]>,
2164    {
2165        DEFAULT_WRITE_OPTS
2166            .with(|opts| self.put_with_ts_opt(key.as_ref(), ts.as_ref(), value.as_ref(), opts))
2167    }
2168
2169    /// Put with timestamp in a specific column family.
2170    /// If "key" already exists, it will coexist with previous entry.
2171    /// `Get` with a timestamp ts specified in ReadOptions will return
2172    /// the most recent key/value whose timestamp is smaller than or equal to ts.
2173    /// Takes an additional argument `ts` as the timestamp.
2174    /// Note: the DB must be opened with user defined timestamp enabled.
2175    pub fn put_cf_with_ts<K, V, S>(
2176        &self,
2177        cf: &impl AsColumnFamilyRef,
2178        key: K,
2179        ts: S,
2180        value: V,
2181    ) -> Result<(), Error>
2182    where
2183        K: AsRef<[u8]>,
2184        V: AsRef<[u8]>,
2185        S: AsRef<[u8]>,
2186    {
2187        DEFAULT_WRITE_OPTS.with(|opts| {
2188            self.put_cf_with_ts_opt(cf, key.as_ref(), ts.as_ref(), value.as_ref(), opts)
2189        })
2190    }
2191
2192    pub fn merge<K, V>(&self, key: K, value: V) -> Result<(), Error>
2193    where
2194        K: AsRef<[u8]>,
2195        V: AsRef<[u8]>,
2196    {
2197        DEFAULT_WRITE_OPTS.with(|opts| self.merge_opt(key, value, opts))
2198    }
2199
2200    pub fn merge_cf<K, V>(&self, cf: &impl AsColumnFamilyRef, key: K, value: V) -> Result<(), Error>
2201    where
2202        K: AsRef<[u8]>,
2203        V: AsRef<[u8]>,
2204    {
2205        DEFAULT_WRITE_OPTS.with(|opts| self.merge_cf_opt(cf, key, value, opts))
2206    }
2207
2208    pub fn delete<K: AsRef<[u8]>>(&self, key: K) -> Result<(), Error> {
2209        DEFAULT_WRITE_OPTS.with(|opts| self.delete_opt(key, opts))
2210    }
2211
2212    pub fn delete_cf<K: AsRef<[u8]>>(
2213        &self,
2214        cf: &impl AsColumnFamilyRef,
2215        key: K,
2216    ) -> Result<(), Error> {
2217        DEFAULT_WRITE_OPTS.with(|opts| self.delete_cf_opt(cf, key, opts))
2218    }
2219
2220    /// Remove the database entry (if any) for "key".
2221    /// Takes an additional argument `ts` as the timestamp.
2222    /// Note: the DB must be opened with user defined timestamp enabled.
2223    pub fn delete_with_ts<K: AsRef<[u8]>, S: AsRef<[u8]>>(
2224        &self,
2225        key: K,
2226        ts: S,
2227    ) -> Result<(), Error> {
2228        DEFAULT_WRITE_OPTS.with(|opts| self.delete_with_ts_opt(key, ts, opts))
2229    }
2230
2231    /// Delete with timestamp in a specific column family.
2232    /// Takes an additional argument `ts` as the timestamp.
2233    /// Note: the DB must be opened with user defined timestamp enabled.
2234    pub fn delete_cf_with_ts<K: AsRef<[u8]>, S: AsRef<[u8]>>(
2235        &self,
2236        cf: &impl AsColumnFamilyRef,
2237        key: K,
2238        ts: S,
2239    ) -> Result<(), Error> {
2240        DEFAULT_WRITE_OPTS.with(|opts| self.delete_cf_with_ts_opt(cf, key, ts, opts))
2241    }
2242
2243    /// Remove the database entry for "key" with WriteOptions.
2244    ///
2245    /// Requires that the key exists and was not overwritten. Returns OK on success,
2246    /// and a non-OK status on error. It is not an error if "key" did not exist in the database.
2247    ///
2248    /// If a key is overwritten (by calling Put() multiple times), then the result
2249    /// of calling SingleDelete() on this key is undefined. SingleDelete() only
2250    /// behaves correctly if there has been only one Put() for this key since the
2251    /// previous call to SingleDelete() for this key.
2252    ///
2253    /// This feature is currently an experimental performance optimization
2254    /// for a very specific workload. It is up to the caller to ensure that
2255    /// SingleDelete is only used for a key that is not deleted using Delete() or
2256    /// written using Merge(). Mixing SingleDelete operations with Deletes and
2257    /// Merges can result in undefined behavior.
2258    ///
2259    /// Note: consider setting options.sync = true.
2260    ///
2261    /// For more information, see <https://github.com/facebook/rocksdb/wiki/Single-Delete>
2262    pub fn single_delete_opt<K: AsRef<[u8]>>(
2263        &self,
2264        key: K,
2265        writeopts: &WriteOptions,
2266    ) -> Result<(), Error> {
2267        let key = key.as_ref();
2268
2269        unsafe {
2270            ffi_try!(ffi::rocksdb_singledelete(
2271                self.inner.inner(),
2272                writeopts.inner,
2273                key.as_ptr() as *const c_char,
2274                key.len() as size_t,
2275            ));
2276            Ok(())
2277        }
2278    }
2279
2280    /// Remove the database entry for "key" from a specific column family with WriteOptions.
2281    ///
2282    /// See single_delete_opt() for detailed behavior and restrictions.
2283    pub fn single_delete_cf_opt<K: AsRef<[u8]>>(
2284        &self,
2285        cf: &impl AsColumnFamilyRef,
2286        key: K,
2287        writeopts: &WriteOptions,
2288    ) -> Result<(), Error> {
2289        let key = key.as_ref();
2290
2291        unsafe {
2292            ffi_try!(ffi::rocksdb_singledelete_cf(
2293                self.inner.inner(),
2294                writeopts.inner,
2295                cf.inner(),
2296                key.as_ptr() as *const c_char,
2297                key.len() as size_t,
2298            ));
2299            Ok(())
2300        }
2301    }
2302
2303    /// Remove the database entry for "key" with WriteOptions.
2304    ///
2305    /// Takes an additional argument `ts` as the timestamp.
2306    /// Note: the DB must be opened with user defined timestamp enabled.
2307    ///
2308    /// See single_delete_opt() for detailed behavior and restrictions.
2309    pub fn single_delete_with_ts_opt<K, S>(
2310        &self,
2311        key: K,
2312        ts: S,
2313        writeopts: &WriteOptions,
2314    ) -> Result<(), Error>
2315    where
2316        K: AsRef<[u8]>,
2317        S: AsRef<[u8]>,
2318    {
2319        let key = key.as_ref();
2320        let ts = ts.as_ref();
2321        unsafe {
2322            ffi_try!(ffi::rocksdb_singledelete_with_ts(
2323                self.inner.inner(),
2324                writeopts.inner,
2325                key.as_ptr() as *const c_char,
2326                key.len() as size_t,
2327                ts.as_ptr() as *const c_char,
2328                ts.len() as size_t,
2329            ));
2330            Ok(())
2331        }
2332    }
2333
2334    /// Remove the database entry for "key" from a specific column family with WriteOptions.
2335    ///
2336    /// Takes an additional argument `ts` as the timestamp.
2337    /// Note: the DB must be opened with user defined timestamp enabled.
2338    ///
2339    /// See single_delete_opt() for detailed behavior and restrictions.
2340    pub fn single_delete_cf_with_ts_opt<K, S>(
2341        &self,
2342        cf: &impl AsColumnFamilyRef,
2343        key: K,
2344        ts: S,
2345        writeopts: &WriteOptions,
2346    ) -> Result<(), Error>
2347    where
2348        K: AsRef<[u8]>,
2349        S: AsRef<[u8]>,
2350    {
2351        let key = key.as_ref();
2352        let ts = ts.as_ref();
2353        unsafe {
2354            ffi_try!(ffi::rocksdb_singledelete_cf_with_ts(
2355                self.inner.inner(),
2356                writeopts.inner,
2357                cf.inner(),
2358                key.as_ptr() as *const c_char,
2359                key.len() as size_t,
2360                ts.as_ptr() as *const c_char,
2361                ts.len() as size_t,
2362            ));
2363            Ok(())
2364        }
2365    }
2366
2367    /// Remove the database entry for "key".
2368    ///
2369    /// See single_delete_opt() for detailed behavior and restrictions.
2370    pub fn single_delete<K: AsRef<[u8]>>(&self, key: K) -> Result<(), Error> {
2371        DEFAULT_WRITE_OPTS.with(|opts| self.single_delete_opt(key, opts))
2372    }
2373
2374    /// Remove the database entry for "key" from a specific column family.
2375    ///
2376    /// See single_delete_opt() for detailed behavior and restrictions.
2377    pub fn single_delete_cf<K: AsRef<[u8]>>(
2378        &self,
2379        cf: &impl AsColumnFamilyRef,
2380        key: K,
2381    ) -> Result<(), Error> {
2382        DEFAULT_WRITE_OPTS.with(|opts| self.single_delete_cf_opt(cf, key, opts))
2383    }
2384
2385    /// Remove the database entry for "key".
2386    ///
2387    /// Takes an additional argument `ts` as the timestamp.
2388    /// Note: the DB must be opened with user defined timestamp enabled.
2389    ///
2390    /// See single_delete_opt() for detailed behavior and restrictions.
2391    pub fn single_delete_with_ts<K: AsRef<[u8]>, S: AsRef<[u8]>>(
2392        &self,
2393        key: K,
2394        ts: S,
2395    ) -> Result<(), Error> {
2396        DEFAULT_WRITE_OPTS.with(|opts| self.single_delete_with_ts_opt(key, ts, opts))
2397    }
2398
2399    /// Remove the database entry for "key" from a specific column family.
2400    ///
2401    /// Takes an additional argument `ts` as the timestamp.
2402    /// Note: the DB must be opened with user defined timestamp enabled.
2403    ///
2404    /// See single_delete_opt() for detailed behavior and restrictions.
2405    pub fn single_delete_cf_with_ts<K: AsRef<[u8]>, S: AsRef<[u8]>>(
2406        &self,
2407        cf: &impl AsColumnFamilyRef,
2408        key: K,
2409        ts: S,
2410    ) -> Result<(), Error> {
2411        DEFAULT_WRITE_OPTS.with(|opts| self.single_delete_cf_with_ts_opt(cf, key, ts, opts))
2412    }
2413
2414    /// Runs a manual compaction on the Range of keys given. This is not likely to be needed for typical usage.
2415    pub fn compact_range<S: AsRef<[u8]>, E: AsRef<[u8]>>(&self, start: Option<S>, end: Option<E>) {
2416        unsafe {
2417            let start = start.as_ref().map(AsRef::as_ref);
2418            let end = end.as_ref().map(AsRef::as_ref);
2419
2420            ffi::rocksdb_compact_range(
2421                self.inner.inner(),
2422                opt_bytes_to_ptr(start),
2423                start.map_or(0, <[u8]>::len) as size_t,
2424                opt_bytes_to_ptr(end),
2425                end.map_or(0, <[u8]>::len) as size_t,
2426            );
2427        }
2428    }
2429
2430    /// Same as `compact_range` but with custom options.
2431    pub fn compact_range_opt<S: AsRef<[u8]>, E: AsRef<[u8]>>(
2432        &self,
2433        start: Option<S>,
2434        end: Option<E>,
2435        opts: &CompactOptions,
2436    ) {
2437        unsafe {
2438            let start = start.as_ref().map(AsRef::as_ref);
2439            let end = end.as_ref().map(AsRef::as_ref);
2440
2441            ffi::rocksdb_compact_range_opt(
2442                self.inner.inner(),
2443                opts.inner,
2444                opt_bytes_to_ptr(start),
2445                start.map_or(0, <[u8]>::len) as size_t,
2446                opt_bytes_to_ptr(end),
2447                end.map_or(0, <[u8]>::len) as size_t,
2448            );
2449        }
2450    }
2451
2452    /// Runs a manual compaction on the Range of keys given on the
2453    /// given column family. This is not likely to be needed for typical usage.
2454    pub fn compact_range_cf<S: AsRef<[u8]>, E: AsRef<[u8]>>(
2455        &self,
2456        cf: &impl AsColumnFamilyRef,
2457        start: Option<S>,
2458        end: Option<E>,
2459    ) {
2460        unsafe {
2461            let start = start.as_ref().map(AsRef::as_ref);
2462            let end = end.as_ref().map(AsRef::as_ref);
2463
2464            ffi::rocksdb_compact_range_cf(
2465                self.inner.inner(),
2466                cf.inner(),
2467                opt_bytes_to_ptr(start),
2468                start.map_or(0, <[u8]>::len) as size_t,
2469                opt_bytes_to_ptr(end),
2470                end.map_or(0, <[u8]>::len) as size_t,
2471            );
2472        }
2473    }
2474
2475    /// Same as `compact_range_cf` but with custom options.
2476    pub fn compact_range_cf_opt<S: AsRef<[u8]>, E: AsRef<[u8]>>(
2477        &self,
2478        cf: &impl AsColumnFamilyRef,
2479        start: Option<S>,
2480        end: Option<E>,
2481        opts: &CompactOptions,
2482    ) {
2483        unsafe {
2484            let start = start.as_ref().map(AsRef::as_ref);
2485            let end = end.as_ref().map(AsRef::as_ref);
2486
2487            ffi::rocksdb_compact_range_cf_opt(
2488                self.inner.inner(),
2489                cf.inner(),
2490                opts.inner,
2491                opt_bytes_to_ptr(start),
2492                start.map_or(0, <[u8]>::len) as size_t,
2493                opt_bytes_to_ptr(end),
2494                end.map_or(0, <[u8]>::len) as size_t,
2495            );
2496        }
2497    }
2498
2499    /// Wait for all flush and compactions jobs to finish. Jobs to wait include the
2500    /// unscheduled (queued, but not scheduled yet).
2501    ///
2502    /// NOTE: This may also never return if there's sufficient ongoing writes that
2503    /// keeps flush and compaction going without stopping. The user would have to
2504    /// cease all the writes to DB to make this eventually return in a stable
2505    /// state. The user may also use timeout option in WaitForCompactOptions to
2506    /// make this stop waiting and return when timeout expires.
2507    pub fn wait_for_compact(&self, opts: &WaitForCompactOptions) -> Result<(), Error> {
2508        unsafe {
2509            ffi_try!(ffi::rocksdb_wait_for_compact(
2510                self.inner.inner(),
2511                opts.inner
2512            ));
2513        }
2514        Ok(())
2515    }
2516
2517    pub fn set_options(&self, opts: &[(&str, &str)]) -> Result<(), Error> {
2518        let copts = convert_options(opts)?;
2519        let cnames: Vec<*const c_char> = copts.iter().map(|opt| opt.0.as_ptr()).collect();
2520        let cvalues: Vec<*const c_char> = copts.iter().map(|opt| opt.1.as_ptr()).collect();
2521        let count = opts.len() as i32;
2522        unsafe {
2523            ffi_try!(ffi::rocksdb_set_options(
2524                self.inner.inner(),
2525                count,
2526                cnames.as_ptr(),
2527                cvalues.as_ptr(),
2528            ));
2529        }
2530        Ok(())
2531    }
2532
2533    pub fn set_options_cf(
2534        &self,
2535        cf: &impl AsColumnFamilyRef,
2536        opts: &[(&str, &str)],
2537    ) -> Result<(), Error> {
2538        let copts = convert_options(opts)?;
2539        let cnames: Vec<*const c_char> = copts.iter().map(|opt| opt.0.as_ptr()).collect();
2540        let cvalues: Vec<*const c_char> = copts.iter().map(|opt| opt.1.as_ptr()).collect();
2541        let count = opts.len() as i32;
2542        unsafe {
2543            ffi_try!(ffi::rocksdb_set_options_cf(
2544                self.inner.inner(),
2545                cf.inner(),
2546                count,
2547                cnames.as_ptr(),
2548                cvalues.as_ptr(),
2549            ));
2550        }
2551        Ok(())
2552    }
2553
2554    /// Implementation for property_value et al methods.
2555    ///
2556    /// `name` is the name of the property.  It will be converted into a CString
2557    /// and passed to `get_property` as argument.  `get_property` reads the
2558    /// specified property and either returns NULL or a pointer to a C allocated
2559    /// string; this method takes ownership of that string and will free it at
2560    /// the end. That string is parsed using `parse` callback which produces
2561    /// the returned result.
2562    fn property_value_impl<R>(
2563        name: impl CStrLike,
2564        get_property: impl FnOnce(*const c_char) -> *mut c_char,
2565        parse: impl FnOnce(&str) -> Result<R, Error>,
2566    ) -> Result<Option<R>, Error> {
2567        let value = match name.bake() {
2568            Ok(prop_name) => get_property(prop_name.as_ptr()),
2569            Err(e) => {
2570                return Err(Error::new(format!(
2571                    "Failed to convert property name to CString: {e}"
2572                )));
2573            }
2574        };
2575        if value.is_null() {
2576            return Ok(None);
2577        }
2578        let result = match unsafe { CStr::from_ptr(value) }.to_str() {
2579            Ok(s) => parse(s).map(|value| Some(value)),
2580            Err(e) => Err(Error::new(format!(
2581                "Failed to convert property value to string: {e}"
2582            ))),
2583        };
2584        unsafe {
2585            ffi::rocksdb_free(value as *mut c_void);
2586        }
2587        result
2588    }
2589
2590    /// Retrieves a RocksDB property by name.
2591    ///
2592    /// Full list of properties could be find
2593    /// [here](https://github.com/facebook/rocksdb/blob/08809f5e6cd9cc4bc3958dd4d59457ae78c76660/include/rocksdb/db.h#L428-L634).
2594    pub fn property_value(&self, name: impl CStrLike) -> Result<Option<String>, Error> {
2595        Self::property_value_impl(
2596            name,
2597            |prop_name| unsafe { ffi::rocksdb_property_value(self.inner.inner(), prop_name) },
2598            |str_value| Ok(str_value.to_owned()),
2599        )
2600    }
2601
2602    /// Retrieves a RocksDB property by name, for a specific column family.
2603    ///
2604    /// Full list of properties could be find
2605    /// [here](https://github.com/facebook/rocksdb/blob/08809f5e6cd9cc4bc3958dd4d59457ae78c76660/include/rocksdb/db.h#L428-L634).
2606    pub fn property_value_cf(
2607        &self,
2608        cf: &impl AsColumnFamilyRef,
2609        name: impl CStrLike,
2610    ) -> Result<Option<String>, Error> {
2611        Self::property_value_impl(
2612            name,
2613            |prop_name| unsafe {
2614                ffi::rocksdb_property_value_cf(self.inner.inner(), cf.inner(), prop_name)
2615            },
2616            |str_value| Ok(str_value.to_owned()),
2617        )
2618    }
2619
2620    fn parse_property_int_value(value: &str) -> Result<u64, Error> {
2621        value.parse::<u64>().map_err(|err| {
2622            Error::new(format!(
2623                "Failed to convert property value {value} to int: {err}"
2624            ))
2625        })
2626    }
2627
2628    /// Retrieves a RocksDB property and casts it to an integer.
2629    ///
2630    /// Full list of properties that return int values could be find
2631    /// [here](https://github.com/facebook/rocksdb/blob/08809f5e6cd9cc4bc3958dd4d59457ae78c76660/include/rocksdb/db.h#L654-L689).
2632    pub fn property_int_value(&self, name: impl CStrLike) -> Result<Option<u64>, Error> {
2633        Self::property_value_impl(
2634            name,
2635            |prop_name| unsafe { ffi::rocksdb_property_value(self.inner.inner(), prop_name) },
2636            Self::parse_property_int_value,
2637        )
2638    }
2639
2640    /// Retrieves a RocksDB property for a specific column family and casts it to an integer.
2641    ///
2642    /// Full list of properties that return int values could be find
2643    /// [here](https://github.com/facebook/rocksdb/blob/08809f5e6cd9cc4bc3958dd4d59457ae78c76660/include/rocksdb/db.h#L654-L689).
2644    pub fn property_int_value_cf(
2645        &self,
2646        cf: &impl AsColumnFamilyRef,
2647        name: impl CStrLike,
2648    ) -> Result<Option<u64>, Error> {
2649        Self::property_value_impl(
2650            name,
2651            |prop_name| unsafe {
2652                ffi::rocksdb_property_value_cf(self.inner.inner(), cf.inner(), prop_name)
2653            },
2654            Self::parse_property_int_value,
2655        )
2656    }
2657
2658    /// The sequence number of the most recent transaction.
2659    pub fn latest_sequence_number(&self) -> u64 {
2660        unsafe { ffi::rocksdb_get_latest_sequence_number(self.inner.inner()) }
2661    }
2662
2663    /// Return the approximate file system space used by keys in each ranges.
2664    ///
2665    /// Note that the returned sizes measure file system space usage, so
2666    /// if the user data compresses by a factor of ten, the returned
2667    /// sizes will be one-tenth the size of the corresponding user data size.
2668    ///
2669    /// Due to lack of abi, only data flushed to disk is taken into account.
2670    pub fn get_approximate_sizes(&self, ranges: &[Range]) -> Vec<u64> {
2671        self.get_approximate_sizes_cfopt(None::<&ColumnFamily>, ranges)
2672    }
2673
2674    pub fn get_approximate_sizes_cf(
2675        &self,
2676        cf: &impl AsColumnFamilyRef,
2677        ranges: &[Range],
2678    ) -> Vec<u64> {
2679        self.get_approximate_sizes_cfopt(Some(cf), ranges)
2680    }
2681
2682    fn get_approximate_sizes_cfopt(
2683        &self,
2684        cf: Option<&impl AsColumnFamilyRef>,
2685        ranges: &[Range],
2686    ) -> Vec<u64> {
2687        let start_keys: Vec<*const c_char> = ranges
2688            .iter()
2689            .map(|x| x.start_key.as_ptr() as *const c_char)
2690            .collect();
2691        let start_key_lens: Vec<_> = ranges.iter().map(|x| x.start_key.len()).collect();
2692        let end_keys: Vec<*const c_char> = ranges
2693            .iter()
2694            .map(|x| x.end_key.as_ptr() as *const c_char)
2695            .collect();
2696        let end_key_lens: Vec<_> = ranges.iter().map(|x| x.end_key.len()).collect();
2697        let mut sizes: Vec<u64> = vec![0; ranges.len()];
2698        let (n, start_key_ptr, start_key_len_ptr, end_key_ptr, end_key_len_ptr, size_ptr) = (
2699            ranges.len() as i32,
2700            start_keys.as_ptr(),
2701            start_key_lens.as_ptr(),
2702            end_keys.as_ptr(),
2703            end_key_lens.as_ptr(),
2704            sizes.as_mut_ptr(),
2705        );
2706        let mut err: *mut c_char = ptr::null_mut();
2707        match cf {
2708            None => unsafe {
2709                ffi::rocksdb_approximate_sizes(
2710                    self.inner.inner(),
2711                    n,
2712                    start_key_ptr,
2713                    start_key_len_ptr,
2714                    end_key_ptr,
2715                    end_key_len_ptr,
2716                    size_ptr,
2717                    &raw mut err,
2718                );
2719            },
2720            Some(cf) => unsafe {
2721                ffi::rocksdb_approximate_sizes_cf(
2722                    self.inner.inner(),
2723                    cf.inner(),
2724                    n,
2725                    start_key_ptr,
2726                    start_key_len_ptr,
2727                    end_key_ptr,
2728                    end_key_len_ptr,
2729                    size_ptr,
2730                    &raw mut err,
2731                );
2732            },
2733        }
2734        sizes
2735    }
2736
2737    /// Iterate over batches of write operations since a given sequence.
2738    ///
2739    /// Produce an iterator that will provide the batches of write operations
2740    /// that have occurred since the given sequence (see
2741    /// `latest_sequence_number()`). Use the provided iterator to retrieve each
2742    /// (`u64`, `WriteBatch`) tuple, and then gather the individual puts and
2743    /// deletes using the `WriteBatch::iterate()` function.
2744    ///
2745    /// Calling `get_updates_since()` with a sequence number that is out of
2746    /// bounds will return an error.
2747    pub fn get_updates_since(&self, seq_number: u64) -> Result<DBWALIterator, Error> {
2748        unsafe {
2749            // rocksdb_wal_readoptions_t does not appear to have any functions
2750            // for creating and destroying it; fortunately we can pass a nullptr
2751            // here to get the default behavior
2752            let opts: *const ffi::rocksdb_wal_readoptions_t = ptr::null();
2753            let iter = ffi_try!(ffi::rocksdb_get_updates_since(
2754                self.inner.inner(),
2755                seq_number,
2756                opts
2757            ));
2758            Ok(DBWALIterator {
2759                inner: iter,
2760                start_seq_number: seq_number,
2761            })
2762        }
2763    }
2764
2765    /// Tries to catch up with the primary by reading as much as possible from the
2766    /// log files.
2767    pub fn try_catch_up_with_primary(&self) -> Result<(), Error> {
2768        unsafe {
2769            ffi_try!(ffi::rocksdb_try_catch_up_with_primary(self.inner.inner()));
2770        }
2771        Ok(())
2772    }
2773
2774    /// Loads a list of external SST files created with SstFileWriter into the DB with default opts
2775    pub fn ingest_external_file<P: AsRef<Path>>(&self, paths: Vec<P>) -> Result<(), Error> {
2776        let opts = IngestExternalFileOptions::default();
2777        self.ingest_external_file_opts(&opts, paths)
2778    }
2779
2780    /// Loads a list of external SST files created with SstFileWriter into the DB
2781    pub fn ingest_external_file_opts<P: AsRef<Path>>(
2782        &self,
2783        opts: &IngestExternalFileOptions,
2784        paths: Vec<P>,
2785    ) -> Result<(), Error> {
2786        let paths_v: Vec<CString> = paths.iter().map(to_cpath).collect::<Result<Vec<_>, _>>()?;
2787        let cpaths: Vec<_> = paths_v.iter().map(|path| path.as_ptr()).collect();
2788
2789        self.ingest_external_file_raw(opts, &paths_v, &cpaths)
2790    }
2791
2792    /// Loads a list of external SST files created with SstFileWriter into the DB for given Column Family
2793    /// with default opts
2794    pub fn ingest_external_file_cf<P: AsRef<Path>>(
2795        &self,
2796        cf: &impl AsColumnFamilyRef,
2797        paths: Vec<P>,
2798    ) -> Result<(), Error> {
2799        let opts = IngestExternalFileOptions::default();
2800        self.ingest_external_file_cf_opts(cf, &opts, paths)
2801    }
2802
2803    /// Loads a list of external SST files created with SstFileWriter into the DB for given Column Family
2804    pub fn ingest_external_file_cf_opts<P: AsRef<Path>>(
2805        &self,
2806        cf: &impl AsColumnFamilyRef,
2807        opts: &IngestExternalFileOptions,
2808        paths: Vec<P>,
2809    ) -> Result<(), Error> {
2810        let paths_v: Vec<CString> = paths.iter().map(to_cpath).collect::<Result<Vec<_>, _>>()?;
2811        let cpaths: Vec<_> = paths_v.iter().map(|path| path.as_ptr()).collect();
2812
2813        self.ingest_external_file_raw_cf(cf, opts, &paths_v, &cpaths)
2814    }
2815
2816    fn ingest_external_file_raw(
2817        &self,
2818        opts: &IngestExternalFileOptions,
2819        paths_v: &[CString],
2820        cpaths: &[*const c_char],
2821    ) -> Result<(), Error> {
2822        unsafe {
2823            ffi_try!(ffi::rocksdb_ingest_external_file(
2824                self.inner.inner(),
2825                cpaths.as_ptr(),
2826                paths_v.len(),
2827                opts.inner.cast_const()
2828            ));
2829            Ok(())
2830        }
2831    }
2832
2833    fn ingest_external_file_raw_cf(
2834        &self,
2835        cf: &impl AsColumnFamilyRef,
2836        opts: &IngestExternalFileOptions,
2837        paths_v: &[CString],
2838        cpaths: &[*const c_char],
2839    ) -> Result<(), Error> {
2840        unsafe {
2841            ffi_try!(ffi::rocksdb_ingest_external_file_cf(
2842                self.inner.inner(),
2843                cf.inner(),
2844                cpaths.as_ptr(),
2845                paths_v.len(),
2846                opts.inner.cast_const()
2847            ));
2848            Ok(())
2849        }
2850    }
2851
2852    /// Obtains the LSM-tree meta data of the default column family of the DB
2853    pub fn get_column_family_metadata(&self) -> ColumnFamilyMetaData {
2854        unsafe {
2855            let ptr = ffi::rocksdb_get_column_family_metadata(self.inner.inner());
2856
2857            let metadata = ColumnFamilyMetaData {
2858                size: ffi::rocksdb_column_family_metadata_get_size(ptr),
2859                name: from_cstr_and_free(ffi::rocksdb_column_family_metadata_get_name(ptr)),
2860                file_count: ffi::rocksdb_column_family_metadata_get_file_count(ptr),
2861            };
2862
2863            // destroy
2864            ffi::rocksdb_column_family_metadata_destroy(ptr);
2865
2866            // return
2867            metadata
2868        }
2869    }
2870
2871    /// Obtains the LSM-tree meta data of the specified column family of the DB
2872    pub fn get_column_family_metadata_cf(
2873        &self,
2874        cf: &impl AsColumnFamilyRef,
2875    ) -> ColumnFamilyMetaData {
2876        unsafe {
2877            let ptr = ffi::rocksdb_get_column_family_metadata_cf(self.inner.inner(), cf.inner());
2878
2879            let metadata = ColumnFamilyMetaData {
2880                size: ffi::rocksdb_column_family_metadata_get_size(ptr),
2881                name: from_cstr_and_free(ffi::rocksdb_column_family_metadata_get_name(ptr)),
2882                file_count: ffi::rocksdb_column_family_metadata_get_file_count(ptr),
2883            };
2884
2885            // destroy
2886            ffi::rocksdb_column_family_metadata_destroy(ptr);
2887
2888            // return
2889            metadata
2890        }
2891    }
2892
2893    /// Returns a list of all table files with their level, start key
2894    /// and end key
2895    pub fn live_files(&self) -> Result<Vec<LiveFile>, Error> {
2896        unsafe {
2897            let livefiles_ptr = ffi::rocksdb_livefiles(self.inner.inner());
2898            if livefiles_ptr.is_null() {
2899                Err(Error::new("Could not get live files".to_owned()))
2900            } else {
2901                let files = LiveFile::from_rocksdb_livefiles_ptr(livefiles_ptr);
2902
2903                // destroy livefiles metadata(s)
2904                ffi::rocksdb_livefiles_destroy(livefiles_ptr);
2905
2906                // return
2907                Ok(files)
2908            }
2909        }
2910    }
2911
2912    /// Delete sst files whose keys are entirely in the given range.
2913    ///
2914    /// Could leave some keys in the range which are in files which are not
2915    /// entirely in the range.
2916    ///
2917    /// Note: L0 files are left regardless of whether they're in the range.
2918    ///
2919    /// SnapshotWithThreadModes before the delete might not see the data in the given range.
2920    pub fn delete_file_in_range<K: AsRef<[u8]>>(&self, from: K, to: K) -> Result<(), Error> {
2921        let from = from.as_ref();
2922        let to = to.as_ref();
2923        unsafe {
2924            ffi_try!(ffi::rocksdb_delete_file_in_range(
2925                self.inner.inner(),
2926                from.as_ptr() as *const c_char,
2927                from.len() as size_t,
2928                to.as_ptr() as *const c_char,
2929                to.len() as size_t,
2930            ));
2931            Ok(())
2932        }
2933    }
2934
2935    /// Same as `delete_file_in_range` but only for specific column family
2936    pub fn delete_file_in_range_cf<K: AsRef<[u8]>>(
2937        &self,
2938        cf: &impl AsColumnFamilyRef,
2939        from: K,
2940        to: K,
2941    ) -> Result<(), Error> {
2942        let from = from.as_ref();
2943        let to = to.as_ref();
2944        unsafe {
2945            ffi_try!(ffi::rocksdb_delete_file_in_range_cf(
2946                self.inner.inner(),
2947                cf.inner(),
2948                from.as_ptr() as *const c_char,
2949                from.len() as size_t,
2950                to.as_ptr() as *const c_char,
2951                to.len() as size_t,
2952            ));
2953            Ok(())
2954        }
2955    }
2956
2957    /// Request stopping background work, if wait is true wait until it's done.
2958    pub fn cancel_all_background_work(&self, wait: bool) {
2959        unsafe {
2960            ffi::rocksdb_cancel_all_background_work(self.inner.inner(), c_uchar::from(wait));
2961        }
2962    }
2963
2964    fn drop_column_family<C>(
2965        &self,
2966        cf_inner: *mut ffi::rocksdb_column_family_handle_t,
2967        cf: C,
2968    ) -> Result<(), Error> {
2969        unsafe {
2970            // first mark the column family as dropped
2971            ffi_try!(ffi::rocksdb_drop_column_family(
2972                self.inner.inner(),
2973                cf_inner
2974            ));
2975        }
2976        // then finally reclaim any resources (mem, files) by destroying the only single column
2977        // family handle by drop()-ing it
2978        drop(cf);
2979        Ok(())
2980    }
2981
2982    /// Increase the full_history_ts of column family. The new ts_low value should
2983    /// be newer than current full_history_ts value.
2984    /// If another thread updates full_history_ts_low concurrently to a higher
2985    /// timestamp than the requested ts_low, a try again error will be returned.
2986    pub fn increase_full_history_ts_low<S: AsRef<[u8]>>(
2987        &self,
2988        cf: &impl AsColumnFamilyRef,
2989        ts: S,
2990    ) -> Result<(), Error> {
2991        let ts = ts.as_ref();
2992        unsafe {
2993            ffi_try!(ffi::rocksdb_increase_full_history_ts_low(
2994                self.inner.inner(),
2995                cf.inner(),
2996                ts.as_ptr() as *const c_char,
2997                ts.len() as size_t,
2998            ));
2999            Ok(())
3000        }
3001    }
3002
3003    /// Get current full_history_ts value.
3004    pub fn get_full_history_ts_low(&self, cf: &impl AsColumnFamilyRef) -> Result<Vec<u8>, Error> {
3005        unsafe {
3006            let mut ts_lowlen = 0;
3007            let ts = ffi_try!(ffi::rocksdb_get_full_history_ts_low(
3008                self.inner.inner(),
3009                cf.inner(),
3010                &raw mut ts_lowlen,
3011            ));
3012
3013            if ts.is_null() {
3014                Err(Error::new("Could not get full_history_ts_low".to_owned()))
3015            } else {
3016                let mut vec = vec![0; ts_lowlen];
3017                ptr::copy_nonoverlapping(ts as *mut u8, vec.as_mut_ptr(), ts_lowlen);
3018                ffi::rocksdb_free(ts as *mut c_void);
3019                Ok(vec)
3020            }
3021        }
3022    }
3023
3024    /// Returns the DB identity. This is typically ASCII bytes, but that is not guaranteed.
3025    pub fn get_db_identity(&self) -> Result<Vec<u8>, Error> {
3026        unsafe {
3027            let mut length: usize = 0;
3028            let identity_ptr = ffi::rocksdb_get_db_identity(self.inner.inner(), &raw mut length);
3029            let identity_vec = raw_data(identity_ptr, length);
3030            ffi::rocksdb_free(identity_ptr as *mut c_void);
3031            // In RocksDB: get_db_identity copies a std::string so it should not fail, but
3032            // the API allows it to be overridden, so it might
3033            identity_vec.ok_or_else(|| Error::new("get_db_identity returned NULL".to_string()))
3034        }
3035    }
3036}
3037
3038impl<I: DBInner> DBCommon<SingleThreaded, I> {
3039    /// Creates column family with given name and options
3040    pub fn create_cf<N: AsRef<str>>(&mut self, name: N, opts: &Options) -> Result<(), Error> {
3041        let inner = self.create_inner_cf_handle(name.as_ref(), opts)?;
3042        self.cfs
3043            .cfs
3044            .insert(name.as_ref().to_string(), ColumnFamily { inner });
3045        Ok(())
3046    }
3047
3048    #[doc = include_str!("db_create_column_family_with_import.md")]
3049    pub fn create_column_family_with_import<N: AsRef<str>>(
3050        &mut self,
3051        options: &Options,
3052        column_family_name: N,
3053        import_options: &ImportColumnFamilyOptions,
3054        metadata: &ExportImportFilesMetaData,
3055    ) -> Result<(), Error> {
3056        let name = column_family_name.as_ref();
3057        let c_name = CString::new(name).map_err(|err| {
3058            Error::new(format!(
3059                "Failed to convert name to CString while importing column family: {err}"
3060            ))
3061        })?;
3062        let inner = unsafe {
3063            ffi_try!(ffi::rocksdb_create_column_family_with_import(
3064                self.inner.inner(),
3065                options.inner,
3066                c_name.as_ptr(),
3067                import_options.inner,
3068                metadata.inner
3069            ))
3070        };
3071        self.cfs
3072            .cfs
3073            .insert(column_family_name.as_ref().into(), ColumnFamily { inner });
3074        Ok(())
3075    }
3076
3077    /// Drops the column family with the given name
3078    pub fn drop_cf(&mut self, name: &str) -> Result<(), Error> {
3079        match self.cfs.cfs.remove(name) {
3080            Some(cf) => self.drop_column_family(cf.inner, cf),
3081            _ => Err(Error::new(format!("Invalid column family: {name}"))),
3082        }
3083    }
3084
3085    /// Returns the underlying column family handle
3086    pub fn cf_handle(&self, name: &str) -> Option<&ColumnFamily> {
3087        self.cfs.cfs.get(name)
3088    }
3089
3090    /// Returns the list of column families currently open.
3091    ///
3092    /// The order of names is unspecified and may vary between calls.
3093    pub fn cf_names(&self) -> Vec<String> {
3094        self.cfs.cfs.keys().cloned().collect()
3095    }
3096}
3097
3098impl<I: DBInner> DBCommon<MultiThreaded, I> {
3099    /// Creates column family with given name and options
3100    pub fn create_cf<N: AsRef<str>>(&self, name: N, opts: &Options) -> Result<(), Error> {
3101        // Note that we acquire the cfs lock before inserting: otherwise we might race
3102        // another caller who observed the handle as missing.
3103        let mut cfs = self.cfs.cfs.write();
3104        let inner = self.create_inner_cf_handle(name.as_ref(), opts)?;
3105        cfs.insert(
3106            name.as_ref().to_string(),
3107            Arc::new(UnboundColumnFamily { inner }),
3108        );
3109        Ok(())
3110    }
3111
3112    #[doc = include_str!("db_create_column_family_with_import.md")]
3113    pub fn create_column_family_with_import<N: AsRef<str>>(
3114        &self,
3115        options: &Options,
3116        column_family_name: N,
3117        import_options: &ImportColumnFamilyOptions,
3118        metadata: &ExportImportFilesMetaData,
3119    ) -> Result<(), Error> {
3120        // Acquire CF lock upfront, before creating the CF, to avoid a race with concurrent creators
3121        let mut cfs = self.cfs.cfs.write();
3122        let name = column_family_name.as_ref();
3123        let c_name = CString::new(name).map_err(|err| {
3124            Error::new(format!(
3125                "Failed to convert name to CString while importing column family: {err}"
3126            ))
3127        })?;
3128        let inner = unsafe {
3129            ffi_try!(ffi::rocksdb_create_column_family_with_import(
3130                self.inner.inner(),
3131                options.inner,
3132                c_name.as_ptr(),
3133                import_options.inner,
3134                metadata.inner
3135            ))
3136        };
3137        cfs.insert(
3138            column_family_name.as_ref().to_string(),
3139            Arc::new(UnboundColumnFamily { inner }),
3140        );
3141        Ok(())
3142    }
3143
3144    /// Drops the column family with the given name by internally locking the inner column
3145    /// family map. This avoids needing `&mut self` reference
3146    pub fn drop_cf(&self, name: &str) -> Result<(), Error> {
3147        match self.cfs.cfs.write().remove(name) {
3148            Some(cf) => self.drop_column_family(cf.inner, cf),
3149            _ => Err(Error::new(format!("Invalid column family: {name}"))),
3150        }
3151    }
3152
3153    /// Returns the underlying column family handle
3154    pub fn cf_handle(&'_ self, name: &str) -> Option<Arc<BoundColumnFamily<'_>>> {
3155        self.cfs
3156            .cfs
3157            .read()
3158            .get(name)
3159            .cloned()
3160            .map(UnboundColumnFamily::bound_column_family)
3161    }
3162
3163    /// Returns the list of column families currently open.
3164    ///
3165    /// The order of names is unspecified and may vary between calls.
3166    pub fn cf_names(&self) -> Vec<String> {
3167        self.cfs.cfs.read().keys().cloned().collect()
3168    }
3169}
3170
3171impl<T: ThreadMode, I: DBInner> Drop for DBCommon<T, I> {
3172    fn drop(&mut self) {
3173        self.cfs.drop_all_cfs_internal();
3174    }
3175}
3176
3177impl<T: ThreadMode, I: DBInner> fmt::Debug for DBCommon<T, I> {
3178    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3179        write!(f, "RocksDB {{ path: {} }}", self.path().display())
3180    }
3181}
3182
3183/// The metadata that describes a column family.
3184#[derive(Debug, Clone)]
3185pub struct ColumnFamilyMetaData {
3186    // The size of this column family in bytes, which is equal to the sum of
3187    // the file size of its "levels".
3188    pub size: u64,
3189    // The name of the column family.
3190    pub name: String,
3191    // The number of files in this column family.
3192    pub file_count: usize,
3193}
3194
3195/// The metadata that describes a SST file
3196#[derive(Debug, Clone)]
3197pub struct LiveFile {
3198    /// Name of the column family the file belongs to
3199    pub column_family_name: String,
3200    /// Name of the file
3201    pub name: String,
3202    /// The directory containing the file, without a trailing '/'. This could be
3203    /// a DB path, wal_dir, etc.
3204    pub directory: String,
3205    /// Size of the file
3206    pub size: usize,
3207    /// Level at which this file resides
3208    pub level: i32,
3209    /// Smallest user defined key in the file
3210    pub start_key: Option<Vec<u8>>,
3211    /// Largest user defined key in the file
3212    pub end_key: Option<Vec<u8>>,
3213    pub smallest_seqno: u64,
3214    pub largest_seqno: u64,
3215    /// Number of entries/alive keys in the file
3216    pub num_entries: u64,
3217    /// Number of deletions/tomb key(s) in the file
3218    pub num_deletions: u64,
3219}
3220
3221impl LiveFile {
3222    /// Create a `Vec<LiveFile>` from a `rocksdb_livefiles_t` pointer
3223    pub(crate) fn from_rocksdb_livefiles_ptr(
3224        files: *const ffi::rocksdb_livefiles_t,
3225    ) -> Vec<LiveFile> {
3226        unsafe {
3227            let n = ffi::rocksdb_livefiles_count(files);
3228
3229            let mut livefiles = Vec::with_capacity(n as usize);
3230            let mut key_size: usize = 0;
3231
3232            for i in 0..n {
3233                // rocksdb_livefiles_* returns pointers to strings, not copies
3234                let column_family_name =
3235                    from_cstr_without_free(ffi::rocksdb_livefiles_column_family_name(files, i));
3236                let name = from_cstr_without_free(ffi::rocksdb_livefiles_name(files, i));
3237                let directory = from_cstr_without_free(ffi::rocksdb_livefiles_directory(files, i));
3238                let size = ffi::rocksdb_livefiles_size(files, i);
3239                let level = ffi::rocksdb_livefiles_level(files, i);
3240
3241                // get smallest key inside file
3242                let smallest_key = ffi::rocksdb_livefiles_smallestkey(files, i, &raw mut key_size);
3243                let smallest_key = raw_data(smallest_key, key_size);
3244
3245                // get largest key inside file
3246                let largest_key = ffi::rocksdb_livefiles_largestkey(files, i, &raw mut key_size);
3247                let largest_key = raw_data(largest_key, key_size);
3248
3249                livefiles.push(LiveFile {
3250                    column_family_name,
3251                    name,
3252                    directory,
3253                    size,
3254                    level,
3255                    start_key: smallest_key,
3256                    end_key: largest_key,
3257                    largest_seqno: ffi::rocksdb_livefiles_largest_seqno(files, i),
3258                    smallest_seqno: ffi::rocksdb_livefiles_smallest_seqno(files, i),
3259                    num_entries: ffi::rocksdb_livefiles_entries(files, i),
3260                    num_deletions: ffi::rocksdb_livefiles_deletions(files, i),
3261                });
3262            }
3263
3264            livefiles
3265        }
3266    }
3267}
3268
3269struct LiveFileGuard(*mut rocksdb_livefile_t);
3270
3271impl LiveFileGuard {
3272    fn into_raw(mut self) -> *mut rocksdb_livefile_t {
3273        let ptr = self.0;
3274        self.0 = ptr::null_mut();
3275        ptr
3276    }
3277}
3278
3279impl Drop for LiveFileGuard {
3280    fn drop(&mut self) {
3281        if !self.0.is_null() {
3282            unsafe {
3283                rocksdb_livefile_destroy(self.0);
3284            }
3285        }
3286    }
3287}
3288
3289struct LiveFilesGuard(*mut rocksdb_livefiles_t);
3290
3291impl LiveFilesGuard {
3292    fn into_raw(mut self) -> *mut rocksdb_livefiles_t {
3293        let ptr = self.0;
3294        self.0 = ptr::null_mut();
3295        ptr
3296    }
3297}
3298
3299impl Drop for LiveFilesGuard {
3300    fn drop(&mut self) {
3301        if !self.0.is_null() {
3302            unsafe {
3303                rocksdb_livefiles_destroy(self.0);
3304            }
3305        }
3306    }
3307}
3308
3309/// Metadata returned as output from [`Checkpoint::export_column_family`][export_column_family] and
3310/// used as input to [`DB::create_column_family_with_import`].
3311///
3312/// [export_column_family]: crate::checkpoint::Checkpoint::export_column_family
3313#[derive(Debug)]
3314pub struct ExportImportFilesMetaData {
3315    pub(crate) inner: *mut ffi::rocksdb_export_import_files_metadata_t,
3316}
3317
3318impl ExportImportFilesMetaData {
3319    pub fn get_db_comparator_name(&self) -> String {
3320        unsafe {
3321            let c_name =
3322                ffi::rocksdb_export_import_files_metadata_get_db_comparator_name(self.inner);
3323            from_cstr_and_free(c_name)
3324        }
3325    }
3326
3327    pub fn set_db_comparator_name(&mut self, name: &str) {
3328        let c_name = CString::new(name.as_bytes()).unwrap();
3329        unsafe {
3330            ffi::rocksdb_export_import_files_metadata_set_db_comparator_name(
3331                self.inner,
3332                c_name.as_ptr(),
3333            );
3334        };
3335    }
3336
3337    pub fn get_files(&self) -> Vec<LiveFile> {
3338        unsafe {
3339            let livefiles_ptr = ffi::rocksdb_export_import_files_metadata_get_files(self.inner);
3340            let files = LiveFile::from_rocksdb_livefiles_ptr(livefiles_ptr);
3341            ffi::rocksdb_livefiles_destroy(livefiles_ptr);
3342            files
3343        }
3344    }
3345
3346    pub fn set_files(&mut self, files: &[LiveFile]) -> Result<(), Error> {
3347        // Use a non-null empty pointer for zero-length keys
3348        static EMPTY: [u8; 0] = [];
3349        let empty_ptr = EMPTY.as_ptr() as *const libc::c_char;
3350
3351        unsafe {
3352            let live_files = LiveFilesGuard(ffi::rocksdb_livefiles_create());
3353
3354            for file in files {
3355                let live_file = LiveFileGuard(ffi::rocksdb_livefile_create());
3356                ffi::rocksdb_livefile_set_level(live_file.0, file.level);
3357
3358                // SAFETY: C strings are copied inside the FFI layer so do not need to be kept alive
3359                let c_cf_name = CString::new(file.column_family_name.as_str()).map_err(|err| {
3360                    Error::new(format!("Unable to convert column family to CString: {err}"))
3361                })?;
3362                ffi::rocksdb_livefile_set_column_family_name(live_file.0, c_cf_name.as_ptr());
3363
3364                let c_name = CString::new(file.name.as_str()).map_err(|err| {
3365                    Error::new(format!("Unable to convert file name to CString: {err}"))
3366                })?;
3367                ffi::rocksdb_livefile_set_name(live_file.0, c_name.as_ptr());
3368
3369                let c_directory = CString::new(file.directory.as_str()).map_err(|err| {
3370                    Error::new(format!("Unable to convert directory to CString: {err}"))
3371                })?;
3372                ffi::rocksdb_livefile_set_directory(live_file.0, c_directory.as_ptr());
3373
3374                ffi::rocksdb_livefile_set_size(live_file.0, file.size);
3375
3376                let (start_key_ptr, start_key_len) = match &file.start_key {
3377                    None => (empty_ptr, 0),
3378                    Some(key) => (key.as_ptr() as *const libc::c_char, key.len()),
3379                };
3380                ffi::rocksdb_livefile_set_smallest_key(live_file.0, start_key_ptr, start_key_len);
3381
3382                let (largest_key_ptr, largest_key_len) = match &file.end_key {
3383                    None => (empty_ptr, 0),
3384                    Some(key) => (key.as_ptr() as *const libc::c_char, key.len()),
3385                };
3386                ffi::rocksdb_livefile_set_largest_key(
3387                    live_file.0,
3388                    largest_key_ptr,
3389                    largest_key_len,
3390                );
3391                ffi::rocksdb_livefile_set_smallest_seqno(live_file.0, file.smallest_seqno);
3392                ffi::rocksdb_livefile_set_largest_seqno(live_file.0, file.largest_seqno);
3393                ffi::rocksdb_livefile_set_num_entries(live_file.0, file.num_entries);
3394                ffi::rocksdb_livefile_set_num_deletions(live_file.0, file.num_deletions);
3395
3396                // moves ownership of live_files into live_file
3397                ffi::rocksdb_livefiles_add(live_files.0, live_file.into_raw());
3398            }
3399
3400            // moves ownership of live_files into inner
3401            ffi::rocksdb_export_import_files_metadata_set_files(self.inner, live_files.into_raw());
3402            Ok(())
3403        }
3404    }
3405}
3406
3407impl Default for ExportImportFilesMetaData {
3408    fn default() -> Self {
3409        let inner = unsafe { ffi::rocksdb_export_import_files_metadata_create() };
3410        assert!(
3411            !inner.is_null(),
3412            "Could not create rocksdb_export_import_files_metadata_t"
3413        );
3414
3415        Self { inner }
3416    }
3417}
3418
3419impl Drop for ExportImportFilesMetaData {
3420    fn drop(&mut self) {
3421        unsafe {
3422            ffi::rocksdb_export_import_files_metadata_destroy(self.inner);
3423        }
3424    }
3425}
3426
3427unsafe impl Send for ExportImportFilesMetaData {}
3428unsafe impl Sync for ExportImportFilesMetaData {}
3429
3430fn convert_options(opts: &[(&str, &str)]) -> Result<Vec<(CString, CString)>, Error> {
3431    opts.iter()
3432        .map(|(name, value)| {
3433            let cname = match CString::new(name.as_bytes()) {
3434                Ok(cname) => cname,
3435                Err(e) => return Err(Error::new(format!("Invalid option name `{e}`"))),
3436            };
3437            let cvalue = match CString::new(value.as_bytes()) {
3438                Ok(cvalue) => cvalue,
3439                Err(e) => return Err(Error::new(format!("Invalid option value: `{e}`"))),
3440            };
3441            Ok((cname, cvalue))
3442        })
3443        .collect()
3444}
3445
3446pub(crate) fn convert_values(
3447    values: Vec<*mut c_char>,
3448    values_sizes: Vec<usize>,
3449    errors: Vec<*mut c_char>,
3450) -> Vec<Result<Option<Vec<u8>>, Error>> {
3451    values
3452        .into_iter()
3453        .zip(values_sizes)
3454        .zip(errors)
3455        .map(|((v, s), e)| {
3456            if e.is_null() {
3457                let value = unsafe { crate::ffi_util::raw_data(v, s) };
3458                unsafe {
3459                    ffi::rocksdb_free(v as *mut c_void);
3460                }
3461                Ok(value)
3462            } else {
3463                Err(convert_rocksdb_error(e))
3464            }
3465        })
3466        .collect()
3467}