electrs_rocksdb/
db_options.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
15use std::ffi::CStr;
16use std::path::Path;
17use std::sync::Arc;
18
19use libc::{self, c_char, c_double, c_int, c_uchar, c_uint, c_void, size_t};
20
21use crate::{
22    compaction_filter::{self, CompactionFilterCallback, CompactionFilterFn},
23    compaction_filter_factory::{self, CompactionFilterFactory},
24    comparator::{self, ComparatorCallback, CompareFn},
25    db::DBAccess,
26    ffi,
27    ffi_util::{to_cpath, CStrLike},
28    merge_operator::{
29        self, full_merge_callback, partial_merge_callback, MergeFn, MergeOperatorCallback,
30    },
31    slice_transform::SliceTransform,
32    Error, SnapshotWithThreadMode,
33};
34
35fn new_cache(capacity: size_t) -> *mut ffi::rocksdb_cache_t {
36    unsafe { ffi::rocksdb_cache_create_lru(capacity) }
37}
38
39pub(crate) struct CacheWrapper {
40    pub(crate) inner: *mut ffi::rocksdb_cache_t,
41}
42
43impl Drop for CacheWrapper {
44    fn drop(&mut self) {
45        unsafe {
46            ffi::rocksdb_cache_destroy(self.inner);
47        }
48    }
49}
50
51#[derive(Clone)]
52pub struct Cache(pub(crate) Arc<CacheWrapper>);
53
54impl Cache {
55    /// Create a lru cache with capacity
56    pub fn new_lru_cache(capacity: size_t) -> Result<Cache, Error> {
57        let cache = new_cache(capacity);
58        if cache.is_null() {
59            Err(Error::new("Could not create Cache".to_owned()))
60        } else {
61            Ok(Cache(Arc::new(CacheWrapper { inner: cache })))
62        }
63    }
64
65    /// Returns the Cache memory usage
66    pub fn get_usage(&self) -> usize {
67        unsafe { ffi::rocksdb_cache_get_usage(self.0.inner) }
68    }
69
70    /// Returns pinned memory usage
71    pub fn get_pinned_usage(&self) -> usize {
72        unsafe { ffi::rocksdb_cache_get_pinned_usage(self.0.inner) }
73    }
74
75    /// Sets cache capacity
76    pub fn set_capacity(&mut self, capacity: size_t) {
77        unsafe {
78            ffi::rocksdb_cache_set_capacity(self.0.inner, capacity);
79        }
80    }
81}
82
83/// An Env is an interface used by the rocksdb implementation to access
84/// operating system functionality like the filesystem etc.  Callers
85/// may wish to provide a custom Env object when opening a database to
86/// get fine gain control; e.g., to rate limit file system operations.
87///
88/// All Env implementations are safe for concurrent access from
89/// multiple threads without any external synchronization.
90///
91/// Note: currently, C API behinds C++ API for various settings.
92/// See also: `rocksdb/include/env.h`
93#[derive(Clone)]
94pub struct Env(Arc<EnvWrapper>);
95
96pub(crate) struct EnvWrapper {
97    inner: *mut ffi::rocksdb_env_t,
98}
99
100impl Drop for EnvWrapper {
101    fn drop(&mut self) {
102        unsafe {
103            ffi::rocksdb_env_destroy(self.inner);
104        }
105    }
106}
107
108impl Env {
109    /// Returns default env
110    pub fn new() -> Result<Self, Error> {
111        let env = unsafe { ffi::rocksdb_create_default_env() };
112        if env.is_null() {
113            Err(Error::new("Could not create mem env".to_owned()))
114        } else {
115            Ok(Self(Arc::new(EnvWrapper { inner: env })))
116        }
117    }
118
119    /// Returns a new environment that stores its data in memory and delegates
120    /// all non-file-storage tasks to base_env.
121    pub fn mem_env() -> Result<Self, Error> {
122        let env = unsafe { ffi::rocksdb_create_mem_env() };
123        if env.is_null() {
124            Err(Error::new("Could not create mem env".to_owned()))
125        } else {
126            Ok(Self(Arc::new(EnvWrapper { inner: env })))
127        }
128    }
129
130    /// Sets the number of background worker threads of a specific thread pool for this environment.
131    /// `LOW` is the default pool.
132    ///
133    /// Default: 1
134    pub fn set_background_threads(&mut self, num_threads: c_int) {
135        unsafe {
136            ffi::rocksdb_env_set_background_threads(self.0.inner, num_threads);
137        }
138    }
139
140    /// Sets the size of the high priority thread pool that can be used to
141    /// prevent compactions from stalling memtable flushes.
142    pub fn set_high_priority_background_threads(&mut self, n: c_int) {
143        unsafe {
144            ffi::rocksdb_env_set_high_priority_background_threads(self.0.inner, n);
145        }
146    }
147
148    /// Sets the size of the low priority thread pool that can be used to
149    /// prevent compactions from stalling memtable flushes.
150    pub fn set_low_priority_background_threads(&mut self, n: c_int) {
151        unsafe {
152            ffi::rocksdb_env_set_low_priority_background_threads(self.0.inner, n);
153        }
154    }
155
156    /// Sets the size of the bottom priority thread pool that can be used to
157    /// prevent compactions from stalling memtable flushes.
158    pub fn set_bottom_priority_background_threads(&mut self, n: c_int) {
159        unsafe {
160            ffi::rocksdb_env_set_bottom_priority_background_threads(self.0.inner, n);
161        }
162    }
163
164    /// Wait for all threads started by StartThread to terminate.
165    pub fn join_all_threads(&mut self) {
166        unsafe {
167            ffi::rocksdb_env_join_all_threads(self.0.inner);
168        }
169    }
170
171    /// Lowering IO priority for threads from the specified pool.
172    pub fn lower_thread_pool_io_priority(&mut self) {
173        unsafe {
174            ffi::rocksdb_env_lower_thread_pool_io_priority(self.0.inner);
175        }
176    }
177
178    /// Lowering IO priority for high priority thread pool.
179    pub fn lower_high_priority_thread_pool_io_priority(&mut self) {
180        unsafe {
181            ffi::rocksdb_env_lower_high_priority_thread_pool_io_priority(self.0.inner);
182        }
183    }
184
185    /// Lowering CPU priority for threads from the specified pool.
186    pub fn lower_thread_pool_cpu_priority(&mut self) {
187        unsafe {
188            ffi::rocksdb_env_lower_thread_pool_cpu_priority(self.0.inner);
189        }
190    }
191
192    /// Lowering CPU priority for high priority thread pool.
193    pub fn lower_high_priority_thread_pool_cpu_priority(&mut self) {
194        unsafe {
195            ffi::rocksdb_env_lower_high_priority_thread_pool_cpu_priority(self.0.inner);
196        }
197    }
198
199    fn clone(&self) -> Self {
200        Self(self.0.clone())
201    }
202}
203
204#[derive(Default)]
205pub(crate) struct OptionsMustOutliveDB {
206    env: Option<Env>,
207    row_cache: Option<Cache>,
208    block_based: Option<BlockBasedOptionsMustOutliveDB>,
209}
210
211impl OptionsMustOutliveDB {
212    pub(crate) fn clone(&self) -> Self {
213        Self {
214            env: self.env.as_ref().map(Env::clone),
215            row_cache: self.row_cache.as_ref().map(Cache::clone),
216            block_based: self
217                .block_based
218                .as_ref()
219                .map(BlockBasedOptionsMustOutliveDB::clone),
220        }
221    }
222}
223
224#[derive(Default)]
225struct BlockBasedOptionsMustOutliveDB {
226    block_cache: Option<Cache>,
227    block_cache_compressed: Option<Cache>,
228}
229
230impl BlockBasedOptionsMustOutliveDB {
231    fn clone(&self) -> Self {
232        Self {
233            block_cache: self.block_cache.as_ref().map(Cache::clone),
234            block_cache_compressed: self.block_cache_compressed.as_ref().map(Cache::clone),
235        }
236    }
237}
238
239/// Database-wide options around performance and behavior.
240///
241/// Please read the official tuning [guide](https://github.com/facebook/rocksdb/wiki/RocksDB-Tuning-Guide)
242/// and most importantly, measure performance under realistic workloads with realistic hardware.
243///
244/// # Examples
245///
246/// ```
247/// use rocksdb::{Options, DB};
248/// use rocksdb::DBCompactionStyle;
249///
250/// fn badly_tuned_for_somebody_elses_disk() -> DB {
251///    let path = "path/for/rocksdb/storageX";
252///    let mut opts = Options::default();
253///    opts.create_if_missing(true);
254///    opts.set_max_open_files(10000);
255///    opts.set_use_fsync(false);
256///    opts.set_bytes_per_sync(8388608);
257///    opts.optimize_for_point_lookup(1024);
258///    opts.set_table_cache_num_shard_bits(6);
259///    opts.set_max_write_buffer_number(32);
260///    opts.set_write_buffer_size(536870912);
261///    opts.set_target_file_size_base(1073741824);
262///    opts.set_min_write_buffer_number_to_merge(4);
263///    opts.set_level_zero_stop_writes_trigger(2000);
264///    opts.set_level_zero_slowdown_writes_trigger(0);
265///    opts.set_compaction_style(DBCompactionStyle::Universal);
266///    opts.set_max_background_compactions(4);
267///    opts.set_max_background_flushes(4);
268///    opts.set_disable_auto_compactions(true);
269///
270///    DB::open(&opts, path).unwrap()
271/// }
272/// ```
273pub struct Options {
274    pub(crate) inner: *mut ffi::rocksdb_options_t,
275    pub(crate) outlive: OptionsMustOutliveDB,
276}
277
278/// Optionally disable WAL or sync for this write.
279///
280/// # Examples
281///
282/// Making an unsafe write of a batch:
283///
284/// ```
285/// use rocksdb::{DB, Options, WriteBatch, WriteOptions};
286///
287/// let path = "_path_for_rocksdb_storageY1";
288/// {
289///     let db = DB::open_default(path).unwrap();
290///     let mut batch = WriteBatch::default();
291///     batch.put(b"my key", b"my value");
292///     batch.put(b"key2", b"value2");
293///     batch.put(b"key3", b"value3");
294///
295///     let mut write_options = WriteOptions::default();
296///     write_options.set_sync(false);
297///     write_options.disable_wal(true);
298///
299///     db.write_opt(batch, &write_options);
300/// }
301/// let _ = DB::destroy(&Options::default(), path);
302/// ```
303pub struct WriteOptions {
304    pub(crate) inner: *mut ffi::rocksdb_writeoptions_t,
305}
306
307/// Optionally wait for the memtable flush to be performed.
308///
309/// # Examples
310///
311/// Manually flushing the memtable:
312///
313/// ```
314/// use rocksdb::{DB, Options, FlushOptions};
315///
316/// let path = "_path_for_rocksdb_storageY2";
317/// {
318///     let db = DB::open_default(path).unwrap();
319///
320///     let mut flush_options = FlushOptions::default();
321///     flush_options.set_wait(true);
322///
323///     db.flush_opt(&flush_options);
324/// }
325/// let _ = DB::destroy(&Options::default(), path);
326/// ```
327pub struct FlushOptions {
328    pub(crate) inner: *mut ffi::rocksdb_flushoptions_t,
329}
330
331/// For configuring block-based file storage.
332pub struct BlockBasedOptions {
333    pub(crate) inner: *mut ffi::rocksdb_block_based_table_options_t,
334    outlive: BlockBasedOptionsMustOutliveDB,
335}
336
337pub struct ReadOptions {
338    pub(crate) inner: *mut ffi::rocksdb_readoptions_t,
339    iterate_upper_bound: Option<Vec<u8>>,
340    iterate_lower_bound: Option<Vec<u8>>,
341}
342
343/// Configuration of cuckoo-based storage.
344pub struct CuckooTableOptions {
345    pub(crate) inner: *mut ffi::rocksdb_cuckoo_table_options_t,
346}
347
348/// For configuring external files ingestion.
349///
350/// # Examples
351///
352/// Move files instead of copying them:
353///
354/// ```
355/// use rocksdb::{DB, IngestExternalFileOptions, SstFileWriter, Options};
356///
357/// let writer_opts = Options::default();
358/// let mut writer = SstFileWriter::create(&writer_opts);
359/// writer.open("_path_for_sst_file").unwrap();
360/// writer.put(b"k1", b"v1").unwrap();
361/// writer.finish().unwrap();
362///
363/// let path = "_path_for_rocksdb_storageY3";
364/// {
365///   let db = DB::open_default(&path).unwrap();
366///   let mut ingest_opts = IngestExternalFileOptions::default();
367///   ingest_opts.set_move_files(true);
368///   db.ingest_external_file_opts(&ingest_opts, vec!["_path_for_sst_file"]).unwrap();
369/// }
370/// let _ = DB::destroy(&Options::default(), path);
371/// ```
372pub struct IngestExternalFileOptions {
373    pub(crate) inner: *mut ffi::rocksdb_ingestexternalfileoptions_t,
374}
375
376// Safety note: auto-implementing Send on most db-related types is prevented by the inner FFI
377// pointer. In most cases, however, this pointer is Send-safe because it is never aliased and
378// rocksdb internally does not rely on thread-local information for its user-exposed types.
379unsafe impl Send for Options {}
380unsafe impl Send for WriteOptions {}
381unsafe impl Send for BlockBasedOptions {}
382unsafe impl Send for CuckooTableOptions {}
383unsafe impl Send for ReadOptions {}
384unsafe impl Send for IngestExternalFileOptions {}
385unsafe impl Send for CacheWrapper {}
386unsafe impl Send for EnvWrapper {}
387
388// Sync is similarly safe for many types because they do not expose interior mutability, and their
389// use within the rocksdb library is generally behind a const reference
390unsafe impl Sync for Options {}
391unsafe impl Sync for WriteOptions {}
392unsafe impl Sync for BlockBasedOptions {}
393unsafe impl Sync for CuckooTableOptions {}
394unsafe impl Sync for ReadOptions {}
395unsafe impl Sync for IngestExternalFileOptions {}
396unsafe impl Sync for CacheWrapper {}
397unsafe impl Sync for EnvWrapper {}
398
399impl Drop for Options {
400    fn drop(&mut self) {
401        unsafe {
402            ffi::rocksdb_options_destroy(self.inner);
403        }
404    }
405}
406
407impl Clone for Options {
408    fn clone(&self) -> Self {
409        let inner = unsafe { ffi::rocksdb_options_create_copy(self.inner) };
410        assert!(!inner.is_null(), "Could not copy RocksDB options");
411
412        Self {
413            inner,
414            outlive: self.outlive.clone(),
415        }
416    }
417}
418
419impl Drop for BlockBasedOptions {
420    fn drop(&mut self) {
421        unsafe {
422            ffi::rocksdb_block_based_options_destroy(self.inner);
423        }
424    }
425}
426
427impl Drop for CuckooTableOptions {
428    fn drop(&mut self) {
429        unsafe {
430            ffi::rocksdb_cuckoo_options_destroy(self.inner);
431        }
432    }
433}
434
435impl Drop for FlushOptions {
436    fn drop(&mut self) {
437        unsafe {
438            ffi::rocksdb_flushoptions_destroy(self.inner);
439        }
440    }
441}
442
443impl Drop for WriteOptions {
444    fn drop(&mut self) {
445        unsafe {
446            ffi::rocksdb_writeoptions_destroy(self.inner);
447        }
448    }
449}
450
451impl Drop for ReadOptions {
452    fn drop(&mut self) {
453        unsafe {
454            ffi::rocksdb_readoptions_destroy(self.inner);
455        }
456    }
457}
458
459impl Drop for IngestExternalFileOptions {
460    fn drop(&mut self) {
461        unsafe {
462            ffi::rocksdb_ingestexternalfileoptions_destroy(self.inner);
463        }
464    }
465}
466
467impl BlockBasedOptions {
468    /// Approximate size of user data packed per block. Note that the
469    /// block size specified here corresponds to uncompressed data. The
470    /// actual size of the unit read from disk may be smaller if
471    /// compression is enabled. This parameter can be changed dynamically.
472    pub fn set_block_size(&mut self, size: usize) {
473        unsafe {
474            ffi::rocksdb_block_based_options_set_block_size(self.inner, size);
475        }
476    }
477
478    /// Block size for partitioned metadata. Currently applied to indexes when
479    /// kTwoLevelIndexSearch is used and to filters when partition_filters is used.
480    /// Note: Since in the current implementation the filters and index partitions
481    /// are aligned, an index/filter block is created when either index or filter
482    /// block size reaches the specified limit.
483    ///
484    /// Note: this limit is currently applied to only index blocks; a filter
485    /// partition is cut right after an index block is cut.
486    pub fn set_metadata_block_size(&mut self, size: usize) {
487        unsafe {
488            ffi::rocksdb_block_based_options_set_metadata_block_size(self.inner, size as u64);
489        }
490    }
491
492    /// Note: currently this option requires kTwoLevelIndexSearch to be set as
493    /// well.
494    ///
495    /// Use partitioned full filters for each SST file. This option is
496    /// incompatible with block-based filters.
497    pub fn set_partition_filters(&mut self, size: bool) {
498        unsafe {
499            ffi::rocksdb_block_based_options_set_partition_filters(self.inner, c_uchar::from(size));
500        }
501    }
502
503    /// When provided: use the specified cache for blocks.
504    /// Otherwise rocksdb will automatically create and use an 8MB internal cache.
505    #[deprecated(
506        since = "0.15.0",
507        note = "This function will be removed in next release. Use set_block_cache instead"
508    )]
509    pub fn set_lru_cache(&mut self, size: size_t) {
510        let cache = new_cache(size);
511        unsafe {
512            // Since cache is wrapped in shared_ptr, we don't need to
513            // call rocksdb_cache_destroy explicitly.
514            ffi::rocksdb_block_based_options_set_block_cache(self.inner, cache);
515        }
516    }
517
518    /// When configured: use the specified cache for compressed blocks.
519    /// Otherwise rocksdb will not use a compressed block cache.
520    ///
521    /// Note: though it looks similar to `block_cache`, RocksDB doesn't put the
522    /// same type of object there.
523    #[deprecated(
524        since = "0.15.0",
525        note = "This function will be removed in next release. Use set_block_cache_compressed instead"
526    )]
527    pub fn set_lru_cache_compressed(&mut self, size: size_t) {
528        let cache = new_cache(size);
529        unsafe {
530            // Since cache is wrapped in shared_ptr, we don't need to
531            // call rocksdb_cache_destroy explicitly.
532            ffi::rocksdb_block_based_options_set_block_cache_compressed(self.inner, cache);
533        }
534    }
535
536    /// Sets global cache for blocks (user data is stored in a set of blocks, and
537    /// a block is the unit of reading from disk). Cache must outlive DB instance which uses it.
538    ///
539    /// If set, use the specified cache for blocks.
540    /// By default, rocksdb will automatically create and use an 8MB internal cache.
541    pub fn set_block_cache(&mut self, cache: &Cache) {
542        unsafe {
543            ffi::rocksdb_block_based_options_set_block_cache(self.inner, cache.0.inner);
544        }
545        self.outlive.block_cache = Some(cache.clone());
546    }
547
548    /// Sets global cache for compressed blocks. Cache must outlive DB instance which uses it.
549    ///
550    /// By default, rocksdb will not use a compressed block cache.
551    pub fn set_block_cache_compressed(&mut self, cache: &Cache) {
552        unsafe {
553            ffi::rocksdb_block_based_options_set_block_cache_compressed(self.inner, cache.0.inner);
554        }
555        self.outlive.block_cache_compressed = Some(cache.clone());
556    }
557
558    /// Disable block cache
559    pub fn disable_cache(&mut self) {
560        unsafe {
561            ffi::rocksdb_block_based_options_set_no_block_cache(self.inner, c_uchar::from(true));
562        }
563    }
564
565    /// Sets a [Bloom filter](https://github.com/facebook/rocksdb/wiki/RocksDB-Bloom-Filter)
566    /// policy to reduce disk reads.
567    ///
568    /// # Examples
569    ///
570    /// ```
571    /// use rocksdb::BlockBasedOptions;
572    ///
573    /// let mut opts = BlockBasedOptions::default();
574    /// opts.set_bloom_filter(10.0, true);
575    /// ```
576    pub fn set_bloom_filter(&mut self, bits_per_key: c_double, block_based: bool) {
577        unsafe {
578            let bloom = if block_based {
579                ffi::rocksdb_filterpolicy_create_bloom(bits_per_key as _)
580            } else {
581                ffi::rocksdb_filterpolicy_create_bloom_full(bits_per_key as _)
582            };
583
584            ffi::rocksdb_block_based_options_set_filter_policy(self.inner, bloom);
585        }
586    }
587
588    /// Sets a [Ribbon filter](http://rocksdb.org/blog/2021/12/29/ribbon-filter.html)
589    /// policy to reduce disk reads.
590    ///
591    /// Ribbon filters use less memory in exchange for slightly more CPU usage
592    /// compared to an equivalent bloom filter.
593    ///
594    /// # Examples
595    ///
596    /// ```
597    /// use rocksdb::BlockBasedOptions;
598    ///
599    /// let mut opts = BlockBasedOptions::default();
600    /// opts.set_ribbon_filter(10.0);
601    /// ```
602    pub fn set_ribbon_filter(&mut self, bloom_equivalent_bits_per_key: c_double) {
603        unsafe {
604            let ribbon = ffi::rocksdb_filterpolicy_create_ribbon(bloom_equivalent_bits_per_key);
605            ffi::rocksdb_block_based_options_set_filter_policy(self.inner, ribbon);
606        }
607    }
608
609    /// Sets a hybrid [Ribbon filter](http://rocksdb.org/blog/2021/12/29/ribbon-filter.html)
610    /// policy to reduce disk reads.
611    ///
612    /// Uses Bloom filters before the given level, and Ribbon filters for all
613    /// other levels. This combines the memory savings from Ribbon filters
614    /// with the lower CPU usage of Bloom filters.
615    ///
616    /// # Examples
617    ///
618    /// ```
619    /// use rocksdb::BlockBasedOptions;
620    ///
621    /// let mut opts = BlockBasedOptions::default();
622    /// opts.set_hybrid_ribbon_filter(10.0, 2);
623    /// ```
624    pub fn set_hybrid_ribbon_filter(
625        &mut self,
626        bloom_equivalent_bits_per_key: c_double,
627        bloom_before_level: c_int,
628    ) {
629        unsafe {
630            let ribbon = ffi::rocksdb_filterpolicy_create_ribbon_hybrid(
631                bloom_equivalent_bits_per_key,
632                bloom_before_level,
633            );
634            ffi::rocksdb_block_based_options_set_filter_policy(self.inner, ribbon);
635        }
636    }
637
638    /// If cache_index_and_filter_blocks is enabled, cache index and filter blocks with high priority.
639    /// If set to true, depending on implementation of block cache,
640    /// index and filter blocks may be less likely to be evicted than data blocks.
641    pub fn set_cache_index_and_filter_blocks(&mut self, v: bool) {
642        unsafe {
643            ffi::rocksdb_block_based_options_set_cache_index_and_filter_blocks(
644                self.inner,
645                c_uchar::from(v),
646            );
647        }
648    }
649
650    /// Defines the index type to be used for SS-table lookups.
651    ///
652    /// # Examples
653    ///
654    /// ```
655    /// use rocksdb::{BlockBasedOptions, BlockBasedIndexType, Options};
656    ///
657    /// let mut opts = Options::default();
658    /// let mut block_opts = BlockBasedOptions::default();
659    /// block_opts.set_index_type(BlockBasedIndexType::HashSearch);
660    /// ```
661    pub fn set_index_type(&mut self, index_type: BlockBasedIndexType) {
662        let index = index_type as i32;
663        unsafe {
664            ffi::rocksdb_block_based_options_set_index_type(self.inner, index);
665        }
666    }
667
668    /// If cache_index_and_filter_blocks is true and the below is true, then
669    /// filter and index blocks are stored in the cache, but a reference is
670    /// held in the "table reader" object so the blocks are pinned and only
671    /// evicted from cache when the table reader is freed.
672    ///
673    /// Default: false.
674    pub fn set_pin_l0_filter_and_index_blocks_in_cache(&mut self, v: bool) {
675        unsafe {
676            ffi::rocksdb_block_based_options_set_pin_l0_filter_and_index_blocks_in_cache(
677                self.inner,
678                c_uchar::from(v),
679            );
680        }
681    }
682
683    /// If cache_index_and_filter_blocks is true and the below is true, then
684    /// the top-level index of partitioned filter and index blocks are stored in
685    /// the cache, but a reference is held in the "table reader" object so the
686    /// blocks are pinned and only evicted from cache when the table reader is
687    /// freed. This is not limited to l0 in LSM tree.
688    ///
689    /// Default: false.
690    pub fn set_pin_top_level_index_and_filter(&mut self, v: bool) {
691        unsafe {
692            ffi::rocksdb_block_based_options_set_pin_top_level_index_and_filter(
693                self.inner,
694                c_uchar::from(v),
695            );
696        }
697    }
698
699    /// Format version, reserved for backward compatibility.
700    ///
701    /// See full [list](https://github.com/facebook/rocksdb/blob/f059c7d9b96300091e07429a60f4ad55dac84859/include/rocksdb/table.h#L249-L274)
702    /// of the supported versions.
703    ///
704    /// Default: 2.
705    pub fn set_format_version(&mut self, version: i32) {
706        unsafe {
707            ffi::rocksdb_block_based_options_set_format_version(self.inner, version);
708        }
709    }
710
711    /// Number of keys between restart points for delta encoding of keys.
712    /// This parameter can be changed dynamically. Most clients should
713    /// leave this parameter alone. The minimum value allowed is 1. Any smaller
714    /// value will be silently overwritten with 1.
715    ///
716    /// Default: 16.
717    pub fn set_block_restart_interval(&mut self, interval: i32) {
718        unsafe {
719            ffi::rocksdb_block_based_options_set_block_restart_interval(self.inner, interval);
720        }
721    }
722
723    /// Same as block_restart_interval but used for the index block.
724    /// If you don't plan to run RocksDB before version 5.16 and you are
725    /// using `index_block_restart_interval` > 1, you should
726    /// probably set the `format_version` to >= 4 as it would reduce the index size.
727    ///
728    /// Default: 1.
729    pub fn set_index_block_restart_interval(&mut self, interval: i32) {
730        unsafe {
731            ffi::rocksdb_block_based_options_set_index_block_restart_interval(self.inner, interval);
732        }
733    }
734
735    /// Set the data block index type for point lookups:
736    ///  `DataBlockIndexType::BinarySearch` to use binary search within the data block.
737    ///  `DataBlockIndexType::BinaryAndHash` to use the data block hash index in combination with
738    ///  the normal binary search.
739    ///
740    /// The hash table utilization ratio is adjustable using [`set_data_block_hash_ratio`](#method.set_data_block_hash_ratio), which is
741    /// valid only when using `DataBlockIndexType::BinaryAndHash`.
742    ///
743    /// Default: `BinarySearch`
744    /// # Examples
745    ///
746    /// ```
747    /// use rocksdb::{BlockBasedOptions, DataBlockIndexType, Options};
748    ///
749    /// let mut opts = Options::default();
750    /// let mut block_opts = BlockBasedOptions::default();
751    /// block_opts.set_data_block_index_type(DataBlockIndexType::BinaryAndHash);
752    /// block_opts.set_data_block_hash_ratio(0.85);
753    /// ```
754    pub fn set_data_block_index_type(&mut self, index_type: DataBlockIndexType) {
755        let index_t = index_type as i32;
756        unsafe {
757            ffi::rocksdb_block_based_options_set_data_block_index_type(self.inner, index_t);
758        }
759    }
760
761    /// Set the data block hash index utilization ratio.
762    ///
763    /// The smaller the utilization ratio, the less hash collisions happen, and so reduce the risk for a
764    /// point lookup to fall back to binary search due to the collisions. A small ratio means faster
765    /// lookup at the price of more space overhead.
766    ///
767    /// Default: 0.75
768    pub fn set_data_block_hash_ratio(&mut self, ratio: f64) {
769        unsafe {
770            ffi::rocksdb_block_based_options_set_data_block_hash_ratio(self.inner, ratio);
771        }
772    }
773
774    /// If false, place only prefixes in the filter, not whole keys.
775    ///
776    /// Defaults to true.
777    pub fn set_whole_key_filtering(&mut self, v: bool) {
778        unsafe {
779            ffi::rocksdb_block_based_options_set_whole_key_filtering(self.inner, c_uchar::from(v));
780        }
781    }
782
783    /// Use the specified checksum type.
784    /// Newly created table files will be protected with this checksum type.
785    /// Old table files will still be readable, even though they have different checksum type.
786    pub fn set_checksum_type(&mut self, checksum_type: ChecksumType) {
787        unsafe {
788            ffi::rocksdb_block_based_options_set_checksum(self.inner, checksum_type as c_char);
789        }
790    }
791}
792
793impl Default for BlockBasedOptions {
794    fn default() -> Self {
795        let block_opts = unsafe { ffi::rocksdb_block_based_options_create() };
796        assert!(
797            !block_opts.is_null(),
798            "Could not create RocksDB block based options"
799        );
800
801        Self {
802            inner: block_opts,
803            outlive: BlockBasedOptionsMustOutliveDB::default(),
804        }
805    }
806}
807
808impl CuckooTableOptions {
809    /// Determines the utilization of hash tables. Smaller values
810    /// result in larger hash tables with fewer collisions.
811    /// Default: 0.9
812    pub fn set_hash_ratio(&mut self, ratio: f64) {
813        unsafe {
814            ffi::rocksdb_cuckoo_options_set_hash_ratio(self.inner, ratio);
815        }
816    }
817
818    /// A property used by builder to determine the depth to go to
819    /// to search for a path to displace elements in case of
820    /// collision. See Builder.MakeSpaceForKey method. Higher
821    /// values result in more efficient hash tables with fewer
822    /// lookups but take more time to build.
823    /// Default: 100
824    pub fn set_max_search_depth(&mut self, depth: u32) {
825        unsafe {
826            ffi::rocksdb_cuckoo_options_set_max_search_depth(self.inner, depth);
827        }
828    }
829
830    /// In case of collision while inserting, the builder
831    /// attempts to insert in the next cuckoo_block_size
832    /// locations before skipping over to the next Cuckoo hash
833    /// function. This makes lookups more cache friendly in case
834    /// of collisions.
835    /// Default: 5
836    pub fn set_cuckoo_block_size(&mut self, size: u32) {
837        unsafe {
838            ffi::rocksdb_cuckoo_options_set_cuckoo_block_size(self.inner, size);
839        }
840    }
841
842    /// If this option is enabled, user key is treated as uint64_t and its value
843    /// is used as hash value directly. This option changes builder's behavior.
844    /// Reader ignore this option and behave according to what specified in
845    /// table property.
846    /// Default: false
847    pub fn set_identity_as_first_hash(&mut self, flag: bool) {
848        unsafe {
849            ffi::rocksdb_cuckoo_options_set_identity_as_first_hash(self.inner, c_uchar::from(flag));
850        }
851    }
852
853    /// If this option is set to true, module is used during hash calculation.
854    /// This often yields better space efficiency at the cost of performance.
855    /// If this option is set to false, # of entries in table is constrained to
856    /// be power of two, and bit and is used to calculate hash, which is faster in general.
857    /// Default: true
858    pub fn set_use_module_hash(&mut self, flag: bool) {
859        unsafe {
860            ffi::rocksdb_cuckoo_options_set_use_module_hash(self.inner, c_uchar::from(flag));
861        }
862    }
863}
864
865impl Default for CuckooTableOptions {
866    fn default() -> Self {
867        let opts = unsafe { ffi::rocksdb_cuckoo_options_create() };
868        assert!(!opts.is_null(), "Could not create RocksDB cuckoo options");
869
870        Self { inner: opts }
871    }
872}
873
874// Verbosity of the LOG.
875#[derive(Debug, Copy, Clone, PartialEq, Eq)]
876#[repr(i32)]
877pub enum LogLevel {
878    Debug = 0,
879    Info,
880    Warn,
881    Error,
882    Fatal,
883    Header,
884}
885
886impl Options {
887    /// By default, RocksDB uses only one background thread for flush and
888    /// compaction. Calling this function will set it up such that total of
889    /// `total_threads` is used. Good value for `total_threads` is the number of
890    /// cores. You almost definitely want to call this function if your system is
891    /// bottlenecked by RocksDB.
892    ///
893    /// # Examples
894    ///
895    /// ```
896    /// use rocksdb::Options;
897    ///
898    /// let mut opts = Options::default();
899    /// opts.increase_parallelism(3);
900    /// ```
901    pub fn increase_parallelism(&mut self, parallelism: i32) {
902        unsafe {
903            ffi::rocksdb_options_increase_parallelism(self.inner, parallelism);
904        }
905    }
906
907    /// Optimize level style compaction.
908    ///
909    /// Default values for some parameters in `Options` are not optimized for heavy
910    /// workloads and big datasets, which means you might observe write stalls under
911    /// some conditions.
912    ///
913    /// This can be used as one of the starting points for tuning RocksDB options in
914    /// such cases.
915    ///
916    /// Internally, it sets `write_buffer_size`, `min_write_buffer_number_to_merge`,
917    /// `max_write_buffer_number`, `level0_file_num_compaction_trigger`,
918    /// `target_file_size_base`, `max_bytes_for_level_base`, so it can override if those
919    /// parameters were set before.
920    ///
921    /// It sets buffer sizes so that memory consumption would be constrained by
922    /// `memtable_memory_budget`.
923    pub fn optimize_level_style_compaction(&mut self, memtable_memory_budget: usize) {
924        unsafe {
925            ffi::rocksdb_options_optimize_level_style_compaction(
926                self.inner,
927                memtable_memory_budget as u64,
928            );
929        }
930    }
931
932    /// Optimize universal style compaction.
933    ///
934    /// Default values for some parameters in `Options` are not optimized for heavy
935    /// workloads and big datasets, which means you might observe write stalls under
936    /// some conditions.
937    ///
938    /// This can be used as one of the starting points for tuning RocksDB options in
939    /// such cases.
940    ///
941    /// Internally, it sets `write_buffer_size`, `min_write_buffer_number_to_merge`,
942    /// `max_write_buffer_number`, `level0_file_num_compaction_trigger`,
943    /// `target_file_size_base`, `max_bytes_for_level_base`, so it can override if those
944    /// parameters were set before.
945    ///
946    /// It sets buffer sizes so that memory consumption would be constrained by
947    /// `memtable_memory_budget`.
948    pub fn optimize_universal_style_compaction(&mut self, memtable_memory_budget: usize) {
949        unsafe {
950            ffi::rocksdb_options_optimize_universal_style_compaction(
951                self.inner,
952                memtable_memory_budget as u64,
953            );
954        }
955    }
956
957    /// If true, the database will be created if it is missing.
958    ///
959    /// Default: `false`
960    ///
961    /// # Examples
962    ///
963    /// ```
964    /// use rocksdb::Options;
965    ///
966    /// let mut opts = Options::default();
967    /// opts.create_if_missing(true);
968    /// ```
969    pub fn create_if_missing(&mut self, create_if_missing: bool) {
970        unsafe {
971            ffi::rocksdb_options_set_create_if_missing(
972                self.inner,
973                c_uchar::from(create_if_missing),
974            );
975        }
976    }
977
978    /// If true, any column families that didn't exist when opening the database
979    /// will be created.
980    ///
981    /// Default: `false`
982    ///
983    /// # Examples
984    ///
985    /// ```
986    /// use rocksdb::Options;
987    ///
988    /// let mut opts = Options::default();
989    /// opts.create_missing_column_families(true);
990    /// ```
991    pub fn create_missing_column_families(&mut self, create_missing_cfs: bool) {
992        unsafe {
993            ffi::rocksdb_options_set_create_missing_column_families(
994                self.inner,
995                c_uchar::from(create_missing_cfs),
996            );
997        }
998    }
999
1000    /// Specifies whether an error should be raised if the database already exists.
1001    ///
1002    /// Default: false
1003    pub fn set_error_if_exists(&mut self, enabled: bool) {
1004        unsafe {
1005            ffi::rocksdb_options_set_error_if_exists(self.inner, c_uchar::from(enabled));
1006        }
1007    }
1008
1009    /// Enable/disable paranoid checks.
1010    ///
1011    /// If true, the implementation will do aggressive checking of the
1012    /// data it is processing and will stop early if it detects any
1013    /// errors. This may have unforeseen ramifications: for example, a
1014    /// corruption of one DB entry may cause a large number of entries to
1015    /// become unreadable or for the entire DB to become unopenable.
1016    /// If any of the  writes to the database fails (Put, Delete, Merge, Write),
1017    /// the database will switch to read-only mode and fail all other
1018    /// Write operations.
1019    ///
1020    /// Default: false
1021    pub fn set_paranoid_checks(&mut self, enabled: bool) {
1022        unsafe {
1023            ffi::rocksdb_options_set_paranoid_checks(self.inner, c_uchar::from(enabled));
1024        }
1025    }
1026
1027    /// A list of paths where SST files can be put into, with its target size.
1028    /// Newer data is placed into paths specified earlier in the vector while
1029    /// older data gradually moves to paths specified later in the vector.
1030    ///
1031    /// For example, you have a flash device with 10GB allocated for the DB,
1032    /// as well as a hard drive of 2TB, you should config it to be:
1033    ///   [{"/flash_path", 10GB}, {"/hard_drive", 2TB}]
1034    ///
1035    /// The system will try to guarantee data under each path is close to but
1036    /// not larger than the target size. But current and future file sizes used
1037    /// by determining where to place a file are based on best-effort estimation,
1038    /// which means there is a chance that the actual size under the directory
1039    /// is slightly more than target size under some workloads. User should give
1040    /// some buffer room for those cases.
1041    ///
1042    /// If none of the paths has sufficient room to place a file, the file will
1043    /// be placed to the last path anyway, despite to the target size.
1044    ///
1045    /// Placing newer data to earlier paths is also best-efforts. User should
1046    /// expect user files to be placed in higher levels in some extreme cases.
1047    ///
1048    /// If left empty, only one path will be used, which is `path` passed when
1049    /// opening the DB.
1050    ///
1051    /// Default: empty
1052    pub fn set_db_paths(&mut self, paths: &[DBPath]) {
1053        let mut paths: Vec<_> = paths
1054            .iter()
1055            .map(|path| path.inner as *const ffi::rocksdb_dbpath_t)
1056            .collect();
1057        let num_paths = paths.len();
1058        unsafe {
1059            ffi::rocksdb_options_set_db_paths(self.inner, paths.as_mut_ptr(), num_paths);
1060        }
1061    }
1062
1063    /// Use the specified object to interact with the environment,
1064    /// e.g. to read/write files, schedule background work, etc. In the near
1065    /// future, support for doing storage operations such as read/write files
1066    /// through env will be deprecated in favor of file_system.
1067    ///
1068    /// Default: Env::default()
1069    pub fn set_env(&mut self, env: &Env) {
1070        unsafe {
1071            ffi::rocksdb_options_set_env(self.inner, env.0.inner);
1072        }
1073        self.outlive.env = Some(env.clone());
1074    }
1075
1076    /// Sets the compression algorithm that will be used for compressing blocks.
1077    ///
1078    /// Default: `DBCompressionType::Snappy` (`DBCompressionType::None` if
1079    /// snappy feature is not enabled).
1080    ///
1081    /// # Examples
1082    ///
1083    /// ```
1084    /// use rocksdb::{Options, DBCompressionType};
1085    ///
1086    /// let mut opts = Options::default();
1087    /// opts.set_compression_type(DBCompressionType::Snappy);
1088    /// ```
1089    pub fn set_compression_type(&mut self, t: DBCompressionType) {
1090        unsafe {
1091            ffi::rocksdb_options_set_compression(self.inner, t as c_int);
1092        }
1093    }
1094
1095    /// Sets the bottom-most compression algorithm that will be used for
1096    /// compressing blocks at the bottom-most level.
1097    ///
1098    /// Note that to actually unable bottom-most compression configuration after
1099    /// setting the compression type it needs to be enabled by calling
1100    /// [`set_bottommost_compression_options`] or
1101    /// [`set_bottommost_zstd_max_train_bytes`] method with `enabled` argument
1102    /// set to `true`.
1103    ///
1104    /// # Examples
1105    ///
1106    /// ```
1107    /// use rocksdb::{Options, DBCompressionType};
1108    ///
1109    /// let mut opts = Options::default();
1110    /// opts.set_bottommost_compression_type(DBCompressionType::Zstd);
1111    /// opts.set_bottommost_zstd_max_train_bytes(0, true);
1112    /// ```
1113    pub fn set_bottommost_compression_type(&mut self, t: DBCompressionType) {
1114        unsafe {
1115            ffi::rocksdb_options_set_bottommost_compression(self.inner, t as c_int);
1116        }
1117    }
1118
1119    /// Different levels can have different compression policies. There
1120    /// are cases where most lower levels would like to use quick compression
1121    /// algorithms while the higher levels (which have more data) use
1122    /// compression algorithms that have better compression but could
1123    /// be slower. This array, if non-empty, should have an entry for
1124    /// each level of the database; these override the value specified in
1125    /// the previous field 'compression'.
1126    ///
1127    /// # Examples
1128    ///
1129    /// ```
1130    /// use rocksdb::{Options, DBCompressionType};
1131    ///
1132    /// let mut opts = Options::default();
1133    /// opts.set_compression_per_level(&[
1134    ///     DBCompressionType::None,
1135    ///     DBCompressionType::None,
1136    ///     DBCompressionType::Snappy,
1137    ///     DBCompressionType::Snappy,
1138    ///     DBCompressionType::Snappy
1139    /// ]);
1140    /// ```
1141    pub fn set_compression_per_level(&mut self, level_types: &[DBCompressionType]) {
1142        unsafe {
1143            let mut level_types: Vec<_> = level_types.iter().map(|&t| t as c_int).collect();
1144            ffi::rocksdb_options_set_compression_per_level(
1145                self.inner,
1146                level_types.as_mut_ptr(),
1147                level_types.len() as size_t,
1148            );
1149        }
1150    }
1151
1152    /// Maximum size of dictionaries used to prime the compression library.
1153    /// Enabling dictionary can improve compression ratios when there are
1154    /// repetitions across data blocks.
1155    ///
1156    /// The dictionary is created by sampling the SST file data. If
1157    /// `zstd_max_train_bytes` is nonzero, the samples are passed through zstd's
1158    /// dictionary generator. Otherwise, the random samples are used directly as
1159    /// the dictionary.
1160    ///
1161    /// When compression dictionary is disabled, we compress and write each block
1162    /// before buffering data for the next one. When compression dictionary is
1163    /// enabled, we buffer all SST file data in-memory so we can sample it, as data
1164    /// can only be compressed and written after the dictionary has been finalized.
1165    /// So users of this feature may see increased memory usage.
1166    ///
1167    /// Default: `0`
1168    ///
1169    /// # Examples
1170    ///
1171    /// ```
1172    /// use rocksdb::Options;
1173    ///
1174    /// let mut opts = Options::default();
1175    /// opts.set_compression_options(4, 5, 6, 7);
1176    /// ```
1177    pub fn set_compression_options(
1178        &mut self,
1179        w_bits: c_int,
1180        level: c_int,
1181        strategy: c_int,
1182        max_dict_bytes: c_int,
1183    ) {
1184        unsafe {
1185            ffi::rocksdb_options_set_compression_options(
1186                self.inner,
1187                w_bits,
1188                level,
1189                strategy,
1190                max_dict_bytes,
1191            );
1192        }
1193    }
1194
1195    /// Sets compression options for blocks at the bottom-most level.  Meaning
1196    /// of all settings is the same as in [`set_compression_options`] method but
1197    /// affect only the bottom-most compression which is set using
1198    /// [`set_bottommost_compression_type`] method.
1199    ///
1200    /// # Examples
1201    ///
1202    /// ```
1203    /// use rocksdb::{Options, DBCompressionType};
1204    ///
1205    /// let mut opts = Options::default();
1206    /// opts.set_bottommost_compression_type(DBCompressionType::Zstd);
1207    /// opts.set_bottommost_compression_options(4, 5, 6, 7, true);
1208    /// ```
1209    pub fn set_bottommost_compression_options(
1210        &mut self,
1211        w_bits: c_int,
1212        level: c_int,
1213        strategy: c_int,
1214        max_dict_bytes: c_int,
1215        enabled: bool,
1216    ) {
1217        unsafe {
1218            ffi::rocksdb_options_set_bottommost_compression_options(
1219                self.inner,
1220                w_bits,
1221                level,
1222                strategy,
1223                max_dict_bytes,
1224                c_uchar::from(enabled),
1225            );
1226        }
1227    }
1228
1229    /// Sets maximum size of training data passed to zstd's dictionary trainer. Using zstd's
1230    /// dictionary trainer can achieve even better compression ratio improvements than using
1231    /// `max_dict_bytes` alone.
1232    ///
1233    /// The training data will be used to generate a dictionary of max_dict_bytes.
1234    ///
1235    /// Default: 0.
1236    pub fn set_zstd_max_train_bytes(&mut self, value: c_int) {
1237        unsafe {
1238            ffi::rocksdb_options_set_compression_options_zstd_max_train_bytes(self.inner, value);
1239        }
1240    }
1241
1242    /// Sets maximum size of training data passed to zstd's dictionary trainer
1243    /// when compressing the bottom-most level. Using zstd's dictionary trainer
1244    /// can achieve even better compression ratio improvements than using
1245    /// `max_dict_bytes` alone.
1246    ///
1247    /// The training data will be used to generate a dictionary of
1248    /// `max_dict_bytes`.
1249    ///
1250    /// Default: 0.
1251    pub fn set_bottommost_zstd_max_train_bytes(&mut self, value: c_int, enabled: bool) {
1252        unsafe {
1253            ffi::rocksdb_options_set_bottommost_compression_options_zstd_max_train_bytes(
1254                self.inner,
1255                value,
1256                c_uchar::from(enabled),
1257            );
1258        }
1259    }
1260
1261    /// If non-zero, we perform bigger reads when doing compaction. If you're
1262    /// running RocksDB on spinning disks, you should set this to at least 2MB.
1263    /// That way RocksDB's compaction is doing sequential instead of random reads.
1264    ///
1265    /// When non-zero, we also force new_table_reader_for_compaction_inputs to
1266    /// true.
1267    ///
1268    /// Default: `0`
1269    pub fn set_compaction_readahead_size(&mut self, compaction_readahead_size: usize) {
1270        unsafe {
1271            ffi::rocksdb_options_compaction_readahead_size(self.inner, compaction_readahead_size);
1272        }
1273    }
1274
1275    /// Allow RocksDB to pick dynamic base of bytes for levels.
1276    /// With this feature turned on, RocksDB will automatically adjust max bytes for each level.
1277    /// The goal of this feature is to have lower bound on size amplification.
1278    ///
1279    /// Default: false.
1280    pub fn set_level_compaction_dynamic_level_bytes(&mut self, v: bool) {
1281        unsafe {
1282            ffi::rocksdb_options_set_level_compaction_dynamic_level_bytes(
1283                self.inner,
1284                c_uchar::from(v),
1285            );
1286        }
1287    }
1288
1289    pub fn set_merge_operator_associative<F: MergeFn + Clone>(
1290        &mut self,
1291        name: impl CStrLike,
1292        full_merge_fn: F,
1293    ) {
1294        let cb = Box::new(MergeOperatorCallback {
1295            name: name.into_c_string().unwrap(),
1296            full_merge_fn: full_merge_fn.clone(),
1297            partial_merge_fn: full_merge_fn,
1298        });
1299
1300        unsafe {
1301            let mo = ffi::rocksdb_mergeoperator_create(
1302                Box::into_raw(cb).cast::<c_void>(),
1303                Some(merge_operator::destructor_callback::<F, F>),
1304                Some(full_merge_callback::<F, F>),
1305                Some(partial_merge_callback::<F, F>),
1306                Some(merge_operator::delete_callback),
1307                Some(merge_operator::name_callback::<F, F>),
1308            );
1309            ffi::rocksdb_options_set_merge_operator(self.inner, mo);
1310        }
1311    }
1312
1313    pub fn set_merge_operator<F: MergeFn, PF: MergeFn>(
1314        &mut self,
1315        name: impl CStrLike,
1316        full_merge_fn: F,
1317        partial_merge_fn: PF,
1318    ) {
1319        let cb = Box::new(MergeOperatorCallback {
1320            name: name.into_c_string().unwrap(),
1321            full_merge_fn,
1322            partial_merge_fn,
1323        });
1324
1325        unsafe {
1326            let mo = ffi::rocksdb_mergeoperator_create(
1327                Box::into_raw(cb).cast::<c_void>(),
1328                Some(merge_operator::destructor_callback::<F, PF>),
1329                Some(full_merge_callback::<F, PF>),
1330                Some(partial_merge_callback::<F, PF>),
1331                Some(merge_operator::delete_callback),
1332                Some(merge_operator::name_callback::<F, PF>),
1333            );
1334            ffi::rocksdb_options_set_merge_operator(self.inner, mo);
1335        }
1336    }
1337
1338    #[deprecated(
1339        since = "0.5.0",
1340        note = "add_merge_operator has been renamed to set_merge_operator"
1341    )]
1342    pub fn add_merge_operator<F: MergeFn + Clone>(&mut self, name: &str, merge_fn: F) {
1343        self.set_merge_operator_associative(name, merge_fn);
1344    }
1345
1346    /// Sets a compaction filter used to determine if entries should be kept, changed,
1347    /// or removed during compaction.
1348    ///
1349    /// An example use case is to remove entries with an expired TTL.
1350    ///
1351    /// If you take a snapshot of the database, only values written since the last
1352    /// snapshot will be passed through the compaction filter.
1353    ///
1354    /// If multi-threaded compaction is used, `filter_fn` may be called multiple times
1355    /// simultaneously.
1356    pub fn set_compaction_filter<F>(&mut self, name: impl CStrLike, filter_fn: F)
1357    where
1358        F: CompactionFilterFn + Send + 'static,
1359    {
1360        let cb = Box::new(CompactionFilterCallback {
1361            name: name.into_c_string().unwrap(),
1362            filter_fn,
1363        });
1364
1365        unsafe {
1366            let cf = ffi::rocksdb_compactionfilter_create(
1367                Box::into_raw(cb).cast::<c_void>(),
1368                Some(compaction_filter::destructor_callback::<CompactionFilterCallback<F>>),
1369                Some(compaction_filter::filter_callback::<CompactionFilterCallback<F>>),
1370                Some(compaction_filter::name_callback::<CompactionFilterCallback<F>>),
1371            );
1372            ffi::rocksdb_options_set_compaction_filter(self.inner, cf);
1373        }
1374    }
1375
1376    /// This is a factory that provides compaction filter objects which allow
1377    /// an application to modify/delete a key-value during background compaction.
1378    ///
1379    /// A new filter will be created on each compaction run.  If multithreaded
1380    /// compaction is being used, each created CompactionFilter will only be used
1381    /// from a single thread and so does not need to be thread-safe.
1382    ///
1383    /// Default: nullptr
1384    pub fn set_compaction_filter_factory<F>(&mut self, factory: F)
1385    where
1386        F: CompactionFilterFactory + 'static,
1387    {
1388        let factory = Box::new(factory);
1389
1390        unsafe {
1391            let cff = ffi::rocksdb_compactionfilterfactory_create(
1392                Box::into_raw(factory).cast::<c_void>(),
1393                Some(compaction_filter_factory::destructor_callback::<F>),
1394                Some(compaction_filter_factory::create_compaction_filter_callback::<F>),
1395                Some(compaction_filter_factory::name_callback::<F>),
1396            );
1397
1398            ffi::rocksdb_options_set_compaction_filter_factory(self.inner, cff);
1399        }
1400    }
1401
1402    /// Sets the comparator used to define the order of keys in the table.
1403    /// Default: a comparator that uses lexicographic byte-wise ordering
1404    ///
1405    /// The client must ensure that the comparator supplied here has the same
1406    /// name and orders keys *exactly* the same as the comparator provided to
1407    /// previous open calls on the same DB.
1408    pub fn set_comparator(&mut self, name: impl CStrLike, compare_fn: CompareFn) {
1409        let cb = Box::new(ComparatorCallback {
1410            name: name.into_c_string().unwrap(),
1411            f: compare_fn,
1412        });
1413
1414        unsafe {
1415            let cmp = ffi::rocksdb_comparator_create(
1416                Box::into_raw(cb).cast::<c_void>(),
1417                Some(comparator::destructor_callback),
1418                Some(comparator::compare_callback),
1419                Some(comparator::name_callback),
1420            );
1421            ffi::rocksdb_options_set_comparator(self.inner, cmp);
1422        }
1423    }
1424
1425    pub fn set_prefix_extractor(&mut self, prefix_extractor: SliceTransform) {
1426        unsafe {
1427            ffi::rocksdb_options_set_prefix_extractor(self.inner, prefix_extractor.inner);
1428        }
1429    }
1430
1431    #[deprecated(
1432        since = "0.5.0",
1433        note = "add_comparator has been renamed to set_comparator"
1434    )]
1435    pub fn add_comparator(&mut self, name: &str, compare_fn: CompareFn) {
1436        self.set_comparator(name, compare_fn);
1437    }
1438
1439    pub fn optimize_for_point_lookup(&mut self, cache_size: u64) {
1440        unsafe {
1441            ffi::rocksdb_options_optimize_for_point_lookup(self.inner, cache_size);
1442        }
1443    }
1444
1445    /// Sets the optimize_filters_for_hits flag
1446    ///
1447    /// Default: `false`
1448    ///
1449    /// # Examples
1450    ///
1451    /// ```
1452    /// use rocksdb::Options;
1453    ///
1454    /// let mut opts = Options::default();
1455    /// opts.set_optimize_filters_for_hits(true);
1456    /// ```
1457    pub fn set_optimize_filters_for_hits(&mut self, optimize_for_hits: bool) {
1458        unsafe {
1459            ffi::rocksdb_options_set_optimize_filters_for_hits(
1460                self.inner,
1461                c_int::from(optimize_for_hits),
1462            );
1463        }
1464    }
1465
1466    /// Sets the periodicity when obsolete files get deleted.
1467    ///
1468    /// The files that get out of scope by compaction
1469    /// process will still get automatically delete on every compaction,
1470    /// regardless of this setting.
1471    ///
1472    /// Default: 6 hours
1473    pub fn set_delete_obsolete_files_period_micros(&mut self, micros: u64) {
1474        unsafe {
1475            ffi::rocksdb_options_set_delete_obsolete_files_period_micros(self.inner, micros);
1476        }
1477    }
1478
1479    /// Prepare the DB for bulk loading.
1480    ///
1481    /// All data will be in level 0 without any automatic compaction.
1482    /// It's recommended to manually call CompactRange(NULL, NULL) before reading
1483    /// from the database, because otherwise the read can be very slow.
1484    pub fn prepare_for_bulk_load(&mut self) {
1485        unsafe {
1486            ffi::rocksdb_options_prepare_for_bulk_load(self.inner);
1487        }
1488    }
1489
1490    /// Sets the number of open files that can be used by the DB. You may need to
1491    /// increase this if your database has a large working set. Value `-1` means
1492    /// files opened are always kept open. You can estimate number of files based
1493    /// on target_file_size_base and target_file_size_multiplier for level-based
1494    /// compaction. For universal-style compaction, you can usually set it to `-1`.
1495    ///
1496    /// Default: `-1`
1497    ///
1498    /// # Examples
1499    ///
1500    /// ```
1501    /// use rocksdb::Options;
1502    ///
1503    /// let mut opts = Options::default();
1504    /// opts.set_max_open_files(10);
1505    /// ```
1506    pub fn set_max_open_files(&mut self, nfiles: c_int) {
1507        unsafe {
1508            ffi::rocksdb_options_set_max_open_files(self.inner, nfiles);
1509        }
1510    }
1511
1512    /// If max_open_files is -1, DB will open all files on DB::Open(). You can
1513    /// use this option to increase the number of threads used to open the files.
1514    /// Default: 16
1515    pub fn set_max_file_opening_threads(&mut self, nthreads: c_int) {
1516        unsafe {
1517            ffi::rocksdb_options_set_max_file_opening_threads(self.inner, nthreads);
1518        }
1519    }
1520
1521    /// By default, writes to stable storage use fdatasync (on platforms
1522    /// where this function is available). If this option is true,
1523    /// fsync is used instead.
1524    ///
1525    /// fsync and fdatasync are equally safe for our purposes and fdatasync is
1526    /// faster, so it is rarely necessary to set this option. It is provided
1527    /// as a workaround for kernel/filesystem bugs, such as one that affected
1528    /// fdatasync with ext4 in kernel versions prior to 3.7.
1529    ///
1530    /// Default: `false`
1531    ///
1532    /// # Examples
1533    ///
1534    /// ```
1535    /// use rocksdb::Options;
1536    ///
1537    /// let mut opts = Options::default();
1538    /// opts.set_use_fsync(true);
1539    /// ```
1540    pub fn set_use_fsync(&mut self, useit: bool) {
1541        unsafe {
1542            ffi::rocksdb_options_set_use_fsync(self.inner, c_int::from(useit));
1543        }
1544    }
1545
1546    /// Specifies the absolute info LOG dir.
1547    ///
1548    /// If it is empty, the log files will be in the same dir as data.
1549    /// If it is non empty, the log files will be in the specified dir,
1550    /// and the db data dir's absolute path will be used as the log file
1551    /// name's prefix.
1552    ///
1553    /// Default: empty
1554    pub fn set_db_log_dir<P: AsRef<Path>>(&mut self, path: P) {
1555        let p = to_cpath(path).unwrap();
1556        unsafe {
1557            ffi::rocksdb_options_set_db_log_dir(self.inner, p.as_ptr());
1558        }
1559    }
1560
1561    /// Specifies the log level.
1562    /// Consider the `LogLevel` enum for a list of possible levels.
1563    ///
1564    /// Default: Info
1565    ///
1566    /// # Examples
1567    ///
1568    /// ```
1569    /// use rocksdb::{Options, LogLevel};
1570    ///
1571    /// let mut opts = Options::default();
1572    /// opts.set_log_level(LogLevel::Warn);
1573    /// ```
1574    pub fn set_log_level(&mut self, level: LogLevel) {
1575        unsafe {
1576            ffi::rocksdb_options_set_info_log_level(self.inner, level as c_int);
1577        }
1578    }
1579
1580    /// Allows OS to incrementally sync files to disk while they are being
1581    /// written, asynchronously, in the background. This operation can be used
1582    /// to smooth out write I/Os over time. Users shouldn't rely on it for
1583    /// persistency guarantee.
1584    /// Issue one request for every bytes_per_sync written. `0` turns it off.
1585    ///
1586    /// Default: `0`
1587    ///
1588    /// You may consider using rate_limiter to regulate write rate to device.
1589    /// When rate limiter is enabled, it automatically enables bytes_per_sync
1590    /// to 1MB.
1591    ///
1592    /// This option applies to table files
1593    ///
1594    /// # Examples
1595    ///
1596    /// ```
1597    /// use rocksdb::Options;
1598    ///
1599    /// let mut opts = Options::default();
1600    /// opts.set_bytes_per_sync(1024 * 1024);
1601    /// ```
1602    pub fn set_bytes_per_sync(&mut self, nbytes: u64) {
1603        unsafe {
1604            ffi::rocksdb_options_set_bytes_per_sync(self.inner, nbytes);
1605        }
1606    }
1607
1608    /// Same as bytes_per_sync, but applies to WAL files.
1609    ///
1610    /// Default: 0, turned off
1611    ///
1612    /// Dynamically changeable through SetDBOptions() API.
1613    pub fn set_wal_bytes_per_sync(&mut self, nbytes: u64) {
1614        unsafe {
1615            ffi::rocksdb_options_set_wal_bytes_per_sync(self.inner, nbytes);
1616        }
1617    }
1618
1619    /// Sets the maximum buffer size that is used by WritableFileWriter.
1620    ///
1621    /// On Windows, we need to maintain an aligned buffer for writes.
1622    /// We allow the buffer to grow until it's size hits the limit in buffered
1623    /// IO and fix the buffer size when using direct IO to ensure alignment of
1624    /// write requests if the logical sector size is unusual
1625    ///
1626    /// Default: 1024 * 1024 (1 MB)
1627    ///
1628    /// Dynamically changeable through SetDBOptions() API.
1629    pub fn set_writable_file_max_buffer_size(&mut self, nbytes: u64) {
1630        unsafe {
1631            ffi::rocksdb_options_set_writable_file_max_buffer_size(self.inner, nbytes);
1632        }
1633    }
1634
1635    /// If true, allow multi-writers to update mem tables in parallel.
1636    /// Only some memtable_factory-s support concurrent writes; currently it
1637    /// is implemented only for SkipListFactory.  Concurrent memtable writes
1638    /// are not compatible with inplace_update_support or filter_deletes.
1639    /// It is strongly recommended to set enable_write_thread_adaptive_yield
1640    /// if you are going to use this feature.
1641    ///
1642    /// Default: true
1643    ///
1644    /// # Examples
1645    ///
1646    /// ```
1647    /// use rocksdb::Options;
1648    ///
1649    /// let mut opts = Options::default();
1650    /// opts.set_allow_concurrent_memtable_write(false);
1651    /// ```
1652    pub fn set_allow_concurrent_memtable_write(&mut self, allow: bool) {
1653        unsafe {
1654            ffi::rocksdb_options_set_allow_concurrent_memtable_write(
1655                self.inner,
1656                c_uchar::from(allow),
1657            );
1658        }
1659    }
1660
1661    /// If true, threads synchronizing with the write batch group leader will wait for up to
1662    /// write_thread_max_yield_usec before blocking on a mutex. This can substantially improve
1663    /// throughput for concurrent workloads, regardless of whether allow_concurrent_memtable_write
1664    /// is enabled.
1665    ///
1666    /// Default: true
1667    pub fn set_enable_write_thread_adaptive_yield(&mut self, enabled: bool) {
1668        unsafe {
1669            ffi::rocksdb_options_set_enable_write_thread_adaptive_yield(
1670                self.inner,
1671                c_uchar::from(enabled),
1672            );
1673        }
1674    }
1675
1676    /// Specifies whether an iteration->Next() sequentially skips over keys with the same user-key or not.
1677    ///
1678    /// This number specifies the number of keys (with the same userkey)
1679    /// that will be sequentially skipped before a reseek is issued.
1680    ///
1681    /// Default: 8
1682    pub fn set_max_sequential_skip_in_iterations(&mut self, num: u64) {
1683        unsafe {
1684            ffi::rocksdb_options_set_max_sequential_skip_in_iterations(self.inner, num);
1685        }
1686    }
1687
1688    /// Enable direct I/O mode for reading
1689    /// they may or may not improve performance depending on the use case
1690    ///
1691    /// Files will be opened in "direct I/O" mode
1692    /// which means that data read from the disk will not be cached or
1693    /// buffered. The hardware buffer of the devices may however still
1694    /// be used. Memory mapped files are not impacted by these parameters.
1695    ///
1696    /// Default: false
1697    ///
1698    /// # Examples
1699    ///
1700    /// ```
1701    /// use rocksdb::Options;
1702    ///
1703    /// let mut opts = Options::default();
1704    /// opts.set_use_direct_reads(true);
1705    /// ```
1706    pub fn set_use_direct_reads(&mut self, enabled: bool) {
1707        unsafe {
1708            ffi::rocksdb_options_set_use_direct_reads(self.inner, c_uchar::from(enabled));
1709        }
1710    }
1711
1712    /// Enable direct I/O mode for flush and compaction
1713    ///
1714    /// Files will be opened in "direct I/O" mode
1715    /// which means that data written to the disk will not be cached or
1716    /// buffered. The hardware buffer of the devices may however still
1717    /// be used. Memory mapped files are not impacted by these parameters.
1718    /// they may or may not improve performance depending on the use case
1719    ///
1720    /// Default: false
1721    ///
1722    /// # Examples
1723    ///
1724    /// ```
1725    /// use rocksdb::Options;
1726    ///
1727    /// let mut opts = Options::default();
1728    /// opts.set_use_direct_io_for_flush_and_compaction(true);
1729    /// ```
1730    pub fn set_use_direct_io_for_flush_and_compaction(&mut self, enabled: bool) {
1731        unsafe {
1732            ffi::rocksdb_options_set_use_direct_io_for_flush_and_compaction(
1733                self.inner,
1734                c_uchar::from(enabled),
1735            );
1736        }
1737    }
1738
1739    /// Enable/dsiable child process inherit open files.
1740    ///
1741    /// Default: true
1742    pub fn set_is_fd_close_on_exec(&mut self, enabled: bool) {
1743        unsafe {
1744            ffi::rocksdb_options_set_is_fd_close_on_exec(self.inner, c_uchar::from(enabled));
1745        }
1746    }
1747
1748    /// Hints to the OS that it should not buffer disk I/O. Enabling this
1749    /// parameter may improve performance but increases pressure on the
1750    /// system cache.
1751    ///
1752    /// The exact behavior of this parameter is platform dependent.
1753    ///
1754    /// On POSIX systems, after RocksDB reads data from disk it will
1755    /// mark the pages as "unneeded". The operating system may - or may not
1756    /// - evict these pages from memory, reducing pressure on the system
1757    /// cache. If the disk block is requested again this can result in
1758    /// additional disk I/O.
1759    ///
1760    /// On WINDOWS systems, files will be opened in "unbuffered I/O" mode
1761    /// which means that data read from the disk will not be cached or
1762    /// bufferized. The hardware buffer of the devices may however still
1763    /// be used. Memory mapped files are not impacted by this parameter.
1764    ///
1765    /// Default: true
1766    ///
1767    /// # Examples
1768    ///
1769    /// ```
1770    /// #[allow(deprecated)]
1771    /// use rocksdb::Options;
1772    ///
1773    /// let mut opts = Options::default();
1774    /// opts.set_allow_os_buffer(false);
1775    /// ```
1776    #[deprecated(
1777        since = "0.7.0",
1778        note = "replaced with set_use_direct_reads/set_use_direct_io_for_flush_and_compaction methods"
1779    )]
1780    pub fn set_allow_os_buffer(&mut self, is_allow: bool) {
1781        self.set_use_direct_reads(!is_allow);
1782        self.set_use_direct_io_for_flush_and_compaction(!is_allow);
1783    }
1784
1785    /// Sets the number of shards used for table cache.
1786    ///
1787    /// Default: `6`
1788    ///
1789    /// # Examples
1790    ///
1791    /// ```
1792    /// use rocksdb::Options;
1793    ///
1794    /// let mut opts = Options::default();
1795    /// opts.set_table_cache_num_shard_bits(4);
1796    /// ```
1797    pub fn set_table_cache_num_shard_bits(&mut self, nbits: c_int) {
1798        unsafe {
1799            ffi::rocksdb_options_set_table_cache_numshardbits(self.inner, nbits);
1800        }
1801    }
1802
1803    /// By default target_file_size_multiplier is 1, which means
1804    /// by default files in different levels will have similar size.
1805    ///
1806    /// Dynamically changeable through SetOptions() API
1807    pub fn set_target_file_size_multiplier(&mut self, multiplier: i32) {
1808        unsafe {
1809            ffi::rocksdb_options_set_target_file_size_multiplier(self.inner, multiplier as c_int);
1810        }
1811    }
1812
1813    /// Sets the minimum number of write buffers that will be merged together
1814    /// before writing to storage.  If set to `1`, then
1815    /// all write buffers are flushed to L0 as individual files and this increases
1816    /// read amplification because a get request has to check in all of these
1817    /// files. Also, an in-memory merge may result in writing lesser
1818    /// data to storage if there are duplicate records in each of these
1819    /// individual write buffers.
1820    ///
1821    /// Default: `1`
1822    ///
1823    /// # Examples
1824    ///
1825    /// ```
1826    /// use rocksdb::Options;
1827    ///
1828    /// let mut opts = Options::default();
1829    /// opts.set_min_write_buffer_number(2);
1830    /// ```
1831    pub fn set_min_write_buffer_number(&mut self, nbuf: c_int) {
1832        unsafe {
1833            ffi::rocksdb_options_set_min_write_buffer_number_to_merge(self.inner, nbuf);
1834        }
1835    }
1836
1837    /// Sets the maximum number of write buffers that are built up in memory.
1838    /// The default and the minimum number is 2, so that when 1 write buffer
1839    /// is being flushed to storage, new writes can continue to the other
1840    /// write buffer.
1841    /// If max_write_buffer_number > 3, writing will be slowed down to
1842    /// options.delayed_write_rate if we are writing to the last write buffer
1843    /// allowed.
1844    ///
1845    /// Default: `2`
1846    ///
1847    /// # Examples
1848    ///
1849    /// ```
1850    /// use rocksdb::Options;
1851    ///
1852    /// let mut opts = Options::default();
1853    /// opts.set_max_write_buffer_number(4);
1854    /// ```
1855    pub fn set_max_write_buffer_number(&mut self, nbuf: c_int) {
1856        unsafe {
1857            ffi::rocksdb_options_set_max_write_buffer_number(self.inner, nbuf);
1858        }
1859    }
1860
1861    /// Sets the amount of data to build up in memory (backed by an unsorted log
1862    /// on disk) before converting to a sorted on-disk file.
1863    ///
1864    /// Larger values increase performance, especially during bulk loads.
1865    /// Up to max_write_buffer_number write buffers may be held in memory
1866    /// at the same time,
1867    /// so you may wish to adjust this parameter to control memory usage.
1868    /// Also, a larger write buffer will result in a longer recovery time
1869    /// the next time the database is opened.
1870    ///
1871    /// Note that write_buffer_size is enforced per column family.
1872    /// See db_write_buffer_size for sharing memory across column families.
1873    ///
1874    /// Default: `0x4000000` (64MiB)
1875    ///
1876    /// Dynamically changeable through SetOptions() API
1877    ///
1878    /// # Examples
1879    ///
1880    /// ```
1881    /// use rocksdb::Options;
1882    ///
1883    /// let mut opts = Options::default();
1884    /// opts.set_write_buffer_size(128 * 1024 * 1024);
1885    /// ```
1886    pub fn set_write_buffer_size(&mut self, size: usize) {
1887        unsafe {
1888            ffi::rocksdb_options_set_write_buffer_size(self.inner, size);
1889        }
1890    }
1891
1892    /// Amount of data to build up in memtables across all column
1893    /// families before writing to disk.
1894    ///
1895    /// This is distinct from write_buffer_size, which enforces a limit
1896    /// for a single memtable.
1897    ///
1898    /// This feature is disabled by default. Specify a non-zero value
1899    /// to enable it.
1900    ///
1901    /// Default: 0 (disabled)
1902    ///
1903    /// # Examples
1904    ///
1905    /// ```
1906    /// use rocksdb::Options;
1907    ///
1908    /// let mut opts = Options::default();
1909    /// opts.set_db_write_buffer_size(128 * 1024 * 1024);
1910    /// ```
1911    pub fn set_db_write_buffer_size(&mut self, size: usize) {
1912        unsafe {
1913            ffi::rocksdb_options_set_db_write_buffer_size(self.inner, size);
1914        }
1915    }
1916
1917    /// Control maximum total data size for a level.
1918    /// max_bytes_for_level_base is the max total for level-1.
1919    /// Maximum number of bytes for level L can be calculated as
1920    /// (max_bytes_for_level_base) * (max_bytes_for_level_multiplier ^ (L-1))
1921    /// For example, if max_bytes_for_level_base is 200MB, and if
1922    /// max_bytes_for_level_multiplier is 10, total data size for level-1
1923    /// will be 200MB, total file size for level-2 will be 2GB,
1924    /// and total file size for level-3 will be 20GB.
1925    ///
1926    /// Default: `0x10000000` (256MiB).
1927    ///
1928    /// Dynamically changeable through SetOptions() API
1929    ///
1930    /// # Examples
1931    ///
1932    /// ```
1933    /// use rocksdb::Options;
1934    ///
1935    /// let mut opts = Options::default();
1936    /// opts.set_max_bytes_for_level_base(512 * 1024 * 1024);
1937    /// ```
1938    pub fn set_max_bytes_for_level_base(&mut self, size: u64) {
1939        unsafe {
1940            ffi::rocksdb_options_set_max_bytes_for_level_base(self.inner, size);
1941        }
1942    }
1943
1944    /// Default: `10`
1945    ///
1946    /// # Examples
1947    ///
1948    /// ```
1949    /// use rocksdb::Options;
1950    ///
1951    /// let mut opts = Options::default();
1952    /// opts.set_max_bytes_for_level_multiplier(4.0);
1953    /// ```
1954    pub fn set_max_bytes_for_level_multiplier(&mut self, mul: f64) {
1955        unsafe {
1956            ffi::rocksdb_options_set_max_bytes_for_level_multiplier(self.inner, mul);
1957        }
1958    }
1959
1960    /// The manifest file is rolled over on reaching this limit.
1961    /// The older manifest file be deleted.
1962    /// The default value is MAX_INT so that roll-over does not take place.
1963    ///
1964    /// # Examples
1965    ///
1966    /// ```
1967    /// use rocksdb::Options;
1968    ///
1969    /// let mut opts = Options::default();
1970    /// opts.set_max_manifest_file_size(20 * 1024 * 1024);
1971    /// ```
1972    pub fn set_max_manifest_file_size(&mut self, size: usize) {
1973        unsafe {
1974            ffi::rocksdb_options_set_max_manifest_file_size(self.inner, size);
1975        }
1976    }
1977
1978    /// Sets the target file size for compaction.
1979    /// target_file_size_base is per-file size for level-1.
1980    /// Target file size for level L can be calculated by
1981    /// target_file_size_base * (target_file_size_multiplier ^ (L-1))
1982    /// For example, if target_file_size_base is 2MB and
1983    /// target_file_size_multiplier is 10, then each file on level-1 will
1984    /// be 2MB, and each file on level 2 will be 20MB,
1985    /// and each file on level-3 will be 200MB.
1986    ///
1987    /// Default: `0x4000000` (64MiB)
1988    ///
1989    /// Dynamically changeable through SetOptions() API
1990    ///
1991    /// # Examples
1992    ///
1993    /// ```
1994    /// use rocksdb::Options;
1995    ///
1996    /// let mut opts = Options::default();
1997    /// opts.set_target_file_size_base(128 * 1024 * 1024);
1998    /// ```
1999    pub fn set_target_file_size_base(&mut self, size: u64) {
2000        unsafe {
2001            ffi::rocksdb_options_set_target_file_size_base(self.inner, size);
2002        }
2003    }
2004
2005    /// Sets the minimum number of write buffers that will be merged together
2006    /// before writing to storage.  If set to `1`, then
2007    /// all write buffers are flushed to L0 as individual files and this increases
2008    /// read amplification because a get request has to check in all of these
2009    /// files. Also, an in-memory merge may result in writing lesser
2010    /// data to storage if there are duplicate records in each of these
2011    /// individual write buffers.
2012    ///
2013    /// Default: `1`
2014    ///
2015    /// # Examples
2016    ///
2017    /// ```
2018    /// use rocksdb::Options;
2019    ///
2020    /// let mut opts = Options::default();
2021    /// opts.set_min_write_buffer_number_to_merge(2);
2022    /// ```
2023    pub fn set_min_write_buffer_number_to_merge(&mut self, to_merge: c_int) {
2024        unsafe {
2025            ffi::rocksdb_options_set_min_write_buffer_number_to_merge(self.inner, to_merge);
2026        }
2027    }
2028
2029    /// Sets the number of files to trigger level-0 compaction. A value < `0` means that
2030    /// level-0 compaction will not be triggered by number of files at all.
2031    ///
2032    /// Default: `4`
2033    ///
2034    /// Dynamically changeable through SetOptions() API
2035    ///
2036    /// # Examples
2037    ///
2038    /// ```
2039    /// use rocksdb::Options;
2040    ///
2041    /// let mut opts = Options::default();
2042    /// opts.set_level_zero_file_num_compaction_trigger(8);
2043    /// ```
2044    pub fn set_level_zero_file_num_compaction_trigger(&mut self, n: c_int) {
2045        unsafe {
2046            ffi::rocksdb_options_set_level0_file_num_compaction_trigger(self.inner, n);
2047        }
2048    }
2049
2050    /// Sets the soft limit on number of level-0 files. We start slowing down writes at this
2051    /// point. A value < `0` means that no writing slow down will be triggered by
2052    /// number of files in level-0.
2053    ///
2054    /// Default: `20`
2055    ///
2056    /// Dynamically changeable through SetOptions() API
2057    ///
2058    /// # Examples
2059    ///
2060    /// ```
2061    /// use rocksdb::Options;
2062    ///
2063    /// let mut opts = Options::default();
2064    /// opts.set_level_zero_slowdown_writes_trigger(10);
2065    /// ```
2066    pub fn set_level_zero_slowdown_writes_trigger(&mut self, n: c_int) {
2067        unsafe {
2068            ffi::rocksdb_options_set_level0_slowdown_writes_trigger(self.inner, n);
2069        }
2070    }
2071
2072    /// Sets the maximum number of level-0 files.  We stop writes at this point.
2073    ///
2074    /// Default: `24`
2075    ///
2076    /// Dynamically changeable through SetOptions() API
2077    ///
2078    /// # Examples
2079    ///
2080    /// ```
2081    /// use rocksdb::Options;
2082    ///
2083    /// let mut opts = Options::default();
2084    /// opts.set_level_zero_stop_writes_trigger(48);
2085    /// ```
2086    pub fn set_level_zero_stop_writes_trigger(&mut self, n: c_int) {
2087        unsafe {
2088            ffi::rocksdb_options_set_level0_stop_writes_trigger(self.inner, n);
2089        }
2090    }
2091
2092    /// Sets the compaction style.
2093    ///
2094    /// Default: DBCompactionStyle::Level
2095    ///
2096    /// # Examples
2097    ///
2098    /// ```
2099    /// use rocksdb::{Options, DBCompactionStyle};
2100    ///
2101    /// let mut opts = Options::default();
2102    /// opts.set_compaction_style(DBCompactionStyle::Universal);
2103    /// ```
2104    pub fn set_compaction_style(&mut self, style: DBCompactionStyle) {
2105        unsafe {
2106            ffi::rocksdb_options_set_compaction_style(self.inner, style as c_int);
2107        }
2108    }
2109
2110    /// Sets the options needed to support Universal Style compactions.
2111    pub fn set_universal_compaction_options(&mut self, uco: &UniversalCompactOptions) {
2112        unsafe {
2113            ffi::rocksdb_options_set_universal_compaction_options(self.inner, uco.inner);
2114        }
2115    }
2116
2117    /// Sets the options for FIFO compaction style.
2118    pub fn set_fifo_compaction_options(&mut self, fco: &FifoCompactOptions) {
2119        unsafe {
2120            ffi::rocksdb_options_set_fifo_compaction_options(self.inner, fco.inner);
2121        }
2122    }
2123
2124    /// Sets unordered_write to true trades higher write throughput with
2125    /// relaxing the immutability guarantee of snapshots. This violates the
2126    /// repeatability one expects from ::Get from a snapshot, as well as
2127    /// ::MultiGet and Iterator's consistent-point-in-time view property.
2128    /// If the application cannot tolerate the relaxed guarantees, it can implement
2129    /// its own mechanisms to work around that and yet benefit from the higher
2130    /// throughput. Using TransactionDB with WRITE_PREPARED write policy and
2131    /// two_write_queues=true is one way to achieve immutable snapshots despite
2132    /// unordered_write.
2133    ///
2134    /// By default, i.e., when it is false, rocksdb does not advance the sequence
2135    /// number for new snapshots unless all the writes with lower sequence numbers
2136    /// are already finished. This provides the immutability that we except from
2137    /// snapshots. Moreover, since Iterator and MultiGet internally depend on
2138    /// snapshots, the snapshot immutability results into Iterator and MultiGet
2139    /// offering consistent-point-in-time view. If set to true, although
2140    /// Read-Your-Own-Write property is still provided, the snapshot immutability
2141    /// property is relaxed: the writes issued after the snapshot is obtained (with
2142    /// larger sequence numbers) will be still not visible to the reads from that
2143    /// snapshot, however, there still might be pending writes (with lower sequence
2144    /// number) that will change the state visible to the snapshot after they are
2145    /// landed to the memtable.
2146    ///
2147    /// Default: false
2148    pub fn set_unordered_write(&mut self, unordered: bool) {
2149        unsafe {
2150            ffi::rocksdb_options_set_unordered_write(self.inner, c_uchar::from(unordered));
2151        }
2152    }
2153
2154    /// Sets maximum number of threads that will
2155    /// concurrently perform a compaction job by breaking it into multiple,
2156    /// smaller ones that are run simultaneously.
2157    ///
2158    /// Default: 1 (i.e. no subcompactions)
2159    pub fn set_max_subcompactions(&mut self, num: u32) {
2160        unsafe {
2161            ffi::rocksdb_options_set_max_subcompactions(self.inner, num);
2162        }
2163    }
2164
2165    /// Sets maximum number of concurrent background jobs
2166    /// (compactions and flushes).
2167    ///
2168    /// Default: 2
2169    ///
2170    /// Dynamically changeable through SetDBOptions() API.
2171    pub fn set_max_background_jobs(&mut self, jobs: c_int) {
2172        unsafe {
2173            ffi::rocksdb_options_set_max_background_jobs(self.inner, jobs);
2174        }
2175    }
2176
2177    /// Sets the maximum number of concurrent background compaction jobs, submitted to
2178    /// the default LOW priority thread pool.
2179    /// We first try to schedule compactions based on
2180    /// `base_background_compactions`. If the compaction cannot catch up , we
2181    /// will increase number of compaction threads up to
2182    /// `max_background_compactions`.
2183    ///
2184    /// If you're increasing this, also consider increasing number of threads in
2185    /// LOW priority thread pool. For more information, see
2186    /// Env::SetBackgroundThreads
2187    ///
2188    /// Default: `1`
2189    ///
2190    /// # Examples
2191    ///
2192    /// ```
2193    /// use rocksdb::Options;
2194    ///
2195    /// let mut opts = Options::default();
2196    /// opts.set_max_background_compactions(2);
2197    /// ```
2198    #[deprecated(
2199        since = "0.15.0",
2200        note = "RocksDB automatically decides this based on the value of max_background_jobs"
2201    )]
2202    pub fn set_max_background_compactions(&mut self, n: c_int) {
2203        unsafe {
2204            ffi::rocksdb_options_set_max_background_compactions(self.inner, n);
2205        }
2206    }
2207
2208    /// Sets the maximum number of concurrent background memtable flush jobs, submitted to
2209    /// the HIGH priority thread pool.
2210    ///
2211    /// By default, all background jobs (major compaction and memtable flush) go
2212    /// to the LOW priority pool. If this option is set to a positive number,
2213    /// memtable flush jobs will be submitted to the HIGH priority pool.
2214    /// It is important when the same Env is shared by multiple db instances.
2215    /// Without a separate pool, long running major compaction jobs could
2216    /// potentially block memtable flush jobs of other db instances, leading to
2217    /// unnecessary Put stalls.
2218    ///
2219    /// If you're increasing this, also consider increasing number of threads in
2220    /// HIGH priority thread pool. For more information, see
2221    /// Env::SetBackgroundThreads
2222    ///
2223    /// Default: `1`
2224    ///
2225    /// # Examples
2226    ///
2227    /// ```
2228    /// use rocksdb::Options;
2229    ///
2230    /// let mut opts = Options::default();
2231    /// opts.set_max_background_flushes(2);
2232    /// ```
2233    #[deprecated(
2234        since = "0.15.0",
2235        note = "RocksDB automatically decides this based on the value of max_background_jobs"
2236    )]
2237    pub fn set_max_background_flushes(&mut self, n: c_int) {
2238        unsafe {
2239            ffi::rocksdb_options_set_max_background_flushes(self.inner, n);
2240        }
2241    }
2242
2243    /// Disables automatic compactions. Manual compactions can still
2244    /// be issued on this column family
2245    ///
2246    /// Default: `false`
2247    ///
2248    /// Dynamically changeable through SetOptions() API
2249    ///
2250    /// # Examples
2251    ///
2252    /// ```
2253    /// use rocksdb::Options;
2254    ///
2255    /// let mut opts = Options::default();
2256    /// opts.set_disable_auto_compactions(true);
2257    /// ```
2258    pub fn set_disable_auto_compactions(&mut self, disable: bool) {
2259        unsafe {
2260            ffi::rocksdb_options_set_disable_auto_compactions(self.inner, c_int::from(disable));
2261        }
2262    }
2263
2264    /// SetMemtableHugePageSize sets the page size for huge page for
2265    /// arena used by the memtable.
2266    /// If <=0, it won't allocate from huge page but from malloc.
2267    /// Users are responsible to reserve huge pages for it to be allocated. For
2268    /// example:
2269    ///      sysctl -w vm.nr_hugepages=20
2270    /// See linux doc Documentation/vm/hugetlbpage.txt
2271    /// If there isn't enough free huge page available, it will fall back to
2272    /// malloc.
2273    ///
2274    /// Dynamically changeable through SetOptions() API
2275    pub fn set_memtable_huge_page_size(&mut self, size: size_t) {
2276        unsafe {
2277            ffi::rocksdb_options_set_memtable_huge_page_size(self.inner, size);
2278        }
2279    }
2280
2281    /// Sets the maximum number of successive merge operations on a key in the memtable.
2282    ///
2283    /// When a merge operation is added to the memtable and the maximum number of
2284    /// successive merges is reached, the value of the key will be calculated and
2285    /// inserted into the memtable instead of the merge operation. This will
2286    /// ensure that there are never more than max_successive_merges merge
2287    /// operations in the memtable.
2288    ///
2289    /// Default: 0 (disabled)
2290    pub fn set_max_successive_merges(&mut self, num: usize) {
2291        unsafe {
2292            ffi::rocksdb_options_set_max_successive_merges(self.inner, num);
2293        }
2294    }
2295
2296    /// Control locality of bloom filter probes to improve cache miss rate.
2297    /// This option only applies to memtable prefix bloom and plaintable
2298    /// prefix bloom. It essentially limits the max number of cache lines each
2299    /// bloom filter check can touch.
2300    ///
2301    /// This optimization is turned off when set to 0. The number should never
2302    /// be greater than number of probes. This option can boost performance
2303    /// for in-memory workload but should use with care since it can cause
2304    /// higher false positive rate.
2305    ///
2306    /// Default: 0
2307    pub fn set_bloom_locality(&mut self, v: u32) {
2308        unsafe {
2309            ffi::rocksdb_options_set_bloom_locality(self.inner, v);
2310        }
2311    }
2312
2313    /// Enable/disable thread-safe inplace updates.
2314    ///
2315    /// Requires updates if
2316    /// * key exists in current memtable
2317    /// * new sizeof(new_value) <= sizeof(old_value)
2318    /// * old_value for that key is a put i.e. kTypeValue
2319    ///
2320    /// Default: false.
2321    pub fn set_inplace_update_support(&mut self, enabled: bool) {
2322        unsafe {
2323            ffi::rocksdb_options_set_inplace_update_support(self.inner, c_uchar::from(enabled));
2324        }
2325    }
2326
2327    /// Sets the number of locks used for inplace update.
2328    ///
2329    /// Default: 10000 when inplace_update_support = true, otherwise 0.
2330    pub fn set_inplace_update_locks(&mut self, num: usize) {
2331        unsafe {
2332            ffi::rocksdb_options_set_inplace_update_num_locks(self.inner, num);
2333        }
2334    }
2335
2336    /// Different max-size multipliers for different levels.
2337    /// These are multiplied by max_bytes_for_level_multiplier to arrive
2338    /// at the max-size of each level.
2339    ///
2340    /// Default: 1
2341    ///
2342    /// Dynamically changeable through SetOptions() API
2343    pub fn set_max_bytes_for_level_multiplier_additional(&mut self, level_values: &[i32]) {
2344        let count = level_values.len();
2345        unsafe {
2346            ffi::rocksdb_options_set_max_bytes_for_level_multiplier_additional(
2347                self.inner,
2348                level_values.as_ptr() as *mut c_int,
2349                count,
2350            );
2351        }
2352    }
2353
2354    /// If true, then DB::Open() will not fetch and check sizes of all sst files.
2355    /// This may significantly speed up startup if there are many sst files,
2356    /// especially when using non-default Env with expensive GetFileSize().
2357    /// We'll still check that all required sst files exist.
2358    /// If paranoid_checks is false, this option is ignored, and sst files are
2359    /// not checked at all.
2360    ///
2361    /// Default: false
2362    pub fn set_skip_checking_sst_file_sizes_on_db_open(&mut self, value: bool) {
2363        unsafe {
2364            ffi::rocksdb_options_set_skip_checking_sst_file_sizes_on_db_open(
2365                self.inner,
2366                c_uchar::from(value),
2367            );
2368        }
2369    }
2370
2371    /// The total maximum size(bytes) of write buffers to maintain in memory
2372    /// including copies of buffers that have already been flushed. This parameter
2373    /// only affects trimming of flushed buffers and does not affect flushing.
2374    /// This controls the maximum amount of write history that will be available
2375    /// in memory for conflict checking when Transactions are used. The actual
2376    /// size of write history (flushed Memtables) might be higher than this limit
2377    /// if further trimming will reduce write history total size below this
2378    /// limit. For example, if max_write_buffer_size_to_maintain is set to 64MB,
2379    /// and there are three flushed Memtables, with sizes of 32MB, 20MB, 20MB.
2380    /// Because trimming the next Memtable of size 20MB will reduce total memory
2381    /// usage to 52MB which is below the limit, RocksDB will stop trimming.
2382    ///
2383    /// When using an OptimisticTransactionDB:
2384    /// If this value is too low, some transactions may fail at commit time due
2385    /// to not being able to determine whether there were any write conflicts.
2386    ///
2387    /// When using a TransactionDB:
2388    /// If Transaction::SetSnapshot is used, TransactionDB will read either
2389    /// in-memory write buffers or SST files to do write-conflict checking.
2390    /// Increasing this value can reduce the number of reads to SST files
2391    /// done for conflict detection.
2392    ///
2393    /// Setting this value to 0 will cause write buffers to be freed immediately
2394    /// after they are flushed. If this value is set to -1,
2395    /// 'max_write_buffer_number * write_buffer_size' will be used.
2396    ///
2397    /// Default:
2398    /// If using a TransactionDB/OptimisticTransactionDB, the default value will
2399    /// be set to the value of 'max_write_buffer_number * write_buffer_size'
2400    /// if it is not explicitly set by the user.  Otherwise, the default is 0.
2401    pub fn set_max_write_buffer_size_to_maintain(&mut self, size: i64) {
2402        unsafe {
2403            ffi::rocksdb_options_set_max_write_buffer_size_to_maintain(self.inner, size);
2404        }
2405    }
2406
2407    /// By default, a single write thread queue is maintained. The thread gets
2408    /// to the head of the queue becomes write batch group leader and responsible
2409    /// for writing to WAL and memtable for the batch group.
2410    ///
2411    /// If enable_pipelined_write is true, separate write thread queue is
2412    /// maintained for WAL write and memtable write. A write thread first enter WAL
2413    /// writer queue and then memtable writer queue. Pending thread on the WAL
2414    /// writer queue thus only have to wait for previous writers to finish their
2415    /// WAL writing but not the memtable writing. Enabling the feature may improve
2416    /// write throughput and reduce latency of the prepare phase of two-phase
2417    /// commit.
2418    ///
2419    /// Default: false
2420    pub fn set_enable_pipelined_write(&mut self, value: bool) {
2421        unsafe {
2422            ffi::rocksdb_options_set_enable_pipelined_write(self.inner, c_uchar::from(value));
2423        }
2424    }
2425
2426    /// Defines the underlying memtable implementation.
2427    /// See official [wiki](https://github.com/facebook/rocksdb/wiki/MemTable) for more information.
2428    /// Defaults to using a skiplist.
2429    ///
2430    /// # Examples
2431    ///
2432    /// ```
2433    /// use rocksdb::{Options, MemtableFactory};
2434    /// let mut opts = Options::default();
2435    /// let factory = MemtableFactory::HashSkipList {
2436    ///     bucket_count: 1_000_000,
2437    ///     height: 4,
2438    ///     branching_factor: 4,
2439    /// };
2440    ///
2441    /// opts.set_allow_concurrent_memtable_write(false);
2442    /// opts.set_memtable_factory(factory);
2443    /// ```
2444    pub fn set_memtable_factory(&mut self, factory: MemtableFactory) {
2445        match factory {
2446            MemtableFactory::Vector => unsafe {
2447                ffi::rocksdb_options_set_memtable_vector_rep(self.inner);
2448            },
2449            MemtableFactory::HashSkipList {
2450                bucket_count,
2451                height,
2452                branching_factor,
2453            } => unsafe {
2454                ffi::rocksdb_options_set_hash_skip_list_rep(
2455                    self.inner,
2456                    bucket_count,
2457                    height,
2458                    branching_factor,
2459                );
2460            },
2461            MemtableFactory::HashLinkList { bucket_count } => unsafe {
2462                ffi::rocksdb_options_set_hash_link_list_rep(self.inner, bucket_count);
2463            },
2464        };
2465    }
2466
2467    pub fn set_block_based_table_factory(&mut self, factory: &BlockBasedOptions) {
2468        unsafe {
2469            ffi::rocksdb_options_set_block_based_table_factory(self.inner, factory.inner);
2470        }
2471        self.outlive.block_based = Some(factory.outlive.clone());
2472    }
2473
2474    /// Sets the table factory to a CuckooTableFactory (the default table
2475    /// factory is a block-based table factory that provides a default
2476    /// implementation of TableBuilder and TableReader with default
2477    /// BlockBasedTableOptions).
2478    /// See official [wiki](https://github.com/facebook/rocksdb/wiki/CuckooTable-Format) for more information on this table format.
2479    /// # Examples
2480    ///
2481    /// ```
2482    /// use rocksdb::{Options, CuckooTableOptions};
2483    ///
2484    /// let mut opts = Options::default();
2485    /// let mut factory_opts = CuckooTableOptions::default();
2486    /// factory_opts.set_hash_ratio(0.8);
2487    /// factory_opts.set_max_search_depth(20);
2488    /// factory_opts.set_cuckoo_block_size(10);
2489    /// factory_opts.set_identity_as_first_hash(true);
2490    /// factory_opts.set_use_module_hash(false);
2491    ///
2492    /// opts.set_cuckoo_table_factory(&factory_opts);
2493    /// ```
2494    pub fn set_cuckoo_table_factory(&mut self, factory: &CuckooTableOptions) {
2495        unsafe {
2496            ffi::rocksdb_options_set_cuckoo_table_factory(self.inner, factory.inner);
2497        }
2498    }
2499
2500    // This is a factory that provides TableFactory objects.
2501    // Default: a block-based table factory that provides a default
2502    // implementation of TableBuilder and TableReader with default
2503    // BlockBasedTableOptions.
2504    /// Sets the factory as plain table.
2505    /// See official [wiki](https://github.com/facebook/rocksdb/wiki/PlainTable-Format) for more
2506    /// information.
2507    ///
2508    /// # Examples
2509    ///
2510    /// ```
2511    /// use rocksdb::{Options, PlainTableFactoryOptions};
2512    ///
2513    /// let mut opts = Options::default();
2514    /// let factory_opts = PlainTableFactoryOptions {
2515    ///   user_key_length: 0,
2516    ///   bloom_bits_per_key: 20,
2517    ///   hash_table_ratio: 0.75,
2518    ///   index_sparseness: 16,
2519    /// };
2520    ///
2521    /// opts.set_plain_table_factory(&factory_opts);
2522    /// ```
2523    pub fn set_plain_table_factory(&mut self, options: &PlainTableFactoryOptions) {
2524        unsafe {
2525            ffi::rocksdb_options_set_plain_table_factory(
2526                self.inner,
2527                options.user_key_length,
2528                options.bloom_bits_per_key,
2529                options.hash_table_ratio,
2530                options.index_sparseness,
2531            );
2532        }
2533    }
2534
2535    /// Sets the start level to use compression.
2536    pub fn set_min_level_to_compress(&mut self, lvl: c_int) {
2537        unsafe {
2538            ffi::rocksdb_options_set_min_level_to_compress(self.inner, lvl);
2539        }
2540    }
2541
2542    /// Measure IO stats in compactions and flushes, if `true`.
2543    ///
2544    /// Default: `false`
2545    ///
2546    /// # Examples
2547    ///
2548    /// ```
2549    /// use rocksdb::Options;
2550    ///
2551    /// let mut opts = Options::default();
2552    /// opts.set_report_bg_io_stats(true);
2553    /// ```
2554    pub fn set_report_bg_io_stats(&mut self, enable: bool) {
2555        unsafe {
2556            ffi::rocksdb_options_set_report_bg_io_stats(self.inner, c_int::from(enable));
2557        }
2558    }
2559
2560    /// Once write-ahead logs exceed this size, we will start forcing the flush of
2561    /// column families whose memtables are backed by the oldest live WAL file
2562    /// (i.e. the ones that are causing all the space amplification).
2563    ///
2564    /// Default: `0`
2565    ///
2566    /// # Examples
2567    ///
2568    /// ```
2569    /// use rocksdb::Options;
2570    ///
2571    /// let mut opts = Options::default();
2572    /// // Set max total wal size to 1G.
2573    /// opts.set_max_total_wal_size(1 << 30);
2574    /// ```
2575    pub fn set_max_total_wal_size(&mut self, size: u64) {
2576        unsafe {
2577            ffi::rocksdb_options_set_max_total_wal_size(self.inner, size);
2578        }
2579    }
2580
2581    /// Recovery mode to control the consistency while replaying WAL.
2582    ///
2583    /// Default: DBRecoveryMode::PointInTime
2584    ///
2585    /// # Examples
2586    ///
2587    /// ```
2588    /// use rocksdb::{Options, DBRecoveryMode};
2589    ///
2590    /// let mut opts = Options::default();
2591    /// opts.set_wal_recovery_mode(DBRecoveryMode::AbsoluteConsistency);
2592    /// ```
2593    pub fn set_wal_recovery_mode(&mut self, mode: DBRecoveryMode) {
2594        unsafe {
2595            ffi::rocksdb_options_set_wal_recovery_mode(self.inner, mode as c_int);
2596        }
2597    }
2598
2599    pub fn enable_statistics(&mut self) {
2600        unsafe {
2601            ffi::rocksdb_options_enable_statistics(self.inner);
2602        }
2603    }
2604
2605    pub fn get_statistics(&self) -> Option<String> {
2606        unsafe {
2607            let value = ffi::rocksdb_options_statistics_get_string(self.inner);
2608            if value.is_null() {
2609                return None;
2610            }
2611
2612            // Must have valid UTF-8 format.
2613            let s = CStr::from_ptr(value).to_str().unwrap().to_owned();
2614            libc::free(value as *mut c_void);
2615            Some(s)
2616        }
2617    }
2618
2619    /// If not zero, dump `rocksdb.stats` to LOG every `stats_dump_period_sec`.
2620    ///
2621    /// Default: `600` (10 mins)
2622    ///
2623    /// # Examples
2624    ///
2625    /// ```
2626    /// use rocksdb::Options;
2627    ///
2628    /// let mut opts = Options::default();
2629    /// opts.set_stats_dump_period_sec(300);
2630    /// ```
2631    pub fn set_stats_dump_period_sec(&mut self, period: c_uint) {
2632        unsafe {
2633            ffi::rocksdb_options_set_stats_dump_period_sec(self.inner, period);
2634        }
2635    }
2636
2637    /// If not zero, dump rocksdb.stats to RocksDB to LOG every `stats_persist_period_sec`.
2638    ///
2639    /// Default: `600` (10 mins)
2640    ///
2641    /// # Examples
2642    ///
2643    /// ```
2644    /// use rocksdb::Options;
2645    ///
2646    /// let mut opts = Options::default();
2647    /// opts.set_stats_persist_period_sec(5);
2648    /// ```
2649    pub fn set_stats_persist_period_sec(&mut self, period: c_uint) {
2650        unsafe {
2651            ffi::rocksdb_options_set_stats_persist_period_sec(self.inner, period);
2652        }
2653    }
2654
2655    /// When set to true, reading SST files will opt out of the filesystem's
2656    /// readahead. Setting this to false may improve sequential iteration
2657    /// performance.
2658    ///
2659    /// Default: `true`
2660    pub fn set_advise_random_on_open(&mut self, advise: bool) {
2661        unsafe {
2662            ffi::rocksdb_options_set_advise_random_on_open(self.inner, c_uchar::from(advise));
2663        }
2664    }
2665
2666    /// Specifies the file access pattern once a compaction is started.
2667    ///
2668    /// It will be applied to all input files of a compaction.
2669    ///
2670    /// Default: Normal
2671    pub fn set_access_hint_on_compaction_start(&mut self, pattern: AccessHint) {
2672        unsafe {
2673            ffi::rocksdb_options_set_access_hint_on_compaction_start(self.inner, pattern as c_int);
2674        }
2675    }
2676
2677    /// Enable/disable adaptive mutex, which spins in the user space before resorting to kernel.
2678    ///
2679    /// This could reduce context switch when the mutex is not
2680    /// heavily contended. However, if the mutex is hot, we could end up
2681    /// wasting spin time.
2682    ///
2683    /// Default: false
2684    pub fn set_use_adaptive_mutex(&mut self, enabled: bool) {
2685        unsafe {
2686            ffi::rocksdb_options_set_use_adaptive_mutex(self.inner, c_uchar::from(enabled));
2687        }
2688    }
2689
2690    /// Sets the number of levels for this database.
2691    pub fn set_num_levels(&mut self, n: c_int) {
2692        unsafe {
2693            ffi::rocksdb_options_set_num_levels(self.inner, n);
2694        }
2695    }
2696
2697    /// When a `prefix_extractor` is defined through `opts.set_prefix_extractor` this
2698    /// creates a prefix bloom filter for each memtable with the size of
2699    /// `write_buffer_size * memtable_prefix_bloom_ratio` (capped at 0.25).
2700    ///
2701    /// Default: `0`
2702    ///
2703    /// # Examples
2704    ///
2705    /// ```
2706    /// use rocksdb::{Options, SliceTransform};
2707    ///
2708    /// let mut opts = Options::default();
2709    /// let transform = SliceTransform::create_fixed_prefix(10);
2710    /// opts.set_prefix_extractor(transform);
2711    /// opts.set_memtable_prefix_bloom_ratio(0.2);
2712    /// ```
2713    pub fn set_memtable_prefix_bloom_ratio(&mut self, ratio: f64) {
2714        unsafe {
2715            ffi::rocksdb_options_set_memtable_prefix_bloom_size_ratio(self.inner, ratio);
2716        }
2717    }
2718
2719    /// Sets the maximum number of bytes in all compacted files.
2720    /// We try to limit number of bytes in one compaction to be lower than this
2721    /// threshold. But it's not guaranteed.
2722    ///
2723    /// Value 0 will be sanitized.
2724    ///
2725    /// Default: target_file_size_base * 25
2726    pub fn set_max_compaction_bytes(&mut self, nbytes: u64) {
2727        unsafe {
2728            ffi::rocksdb_options_set_max_compaction_bytes(self.inner, nbytes);
2729        }
2730    }
2731
2732    /// Specifies the absolute path of the directory the
2733    /// write-ahead log (WAL) should be written to.
2734    ///
2735    /// Default: same directory as the database
2736    ///
2737    /// # Examples
2738    ///
2739    /// ```
2740    /// use rocksdb::Options;
2741    ///
2742    /// let mut opts = Options::default();
2743    /// opts.set_wal_dir("/path/to/dir");
2744    /// ```
2745    pub fn set_wal_dir<P: AsRef<Path>>(&mut self, path: P) {
2746        let p = to_cpath(path).unwrap();
2747        unsafe {
2748            ffi::rocksdb_options_set_wal_dir(self.inner, p.as_ptr());
2749        }
2750    }
2751
2752    /// Sets the WAL ttl in seconds.
2753    ///
2754    /// The following two options affect how archived logs will be deleted.
2755    /// 1. If both set to 0, logs will be deleted asap and will not get into
2756    ///    the archive.
2757    /// 2. If wal_ttl_seconds is 0 and wal_size_limit_mb is not 0,
2758    ///    WAL files will be checked every 10 min and if total size is greater
2759    ///    then wal_size_limit_mb, they will be deleted starting with the
2760    ///    earliest until size_limit is met. All empty files will be deleted.
2761    /// 3. If wal_ttl_seconds is not 0 and wall_size_limit_mb is 0, then
2762    ///    WAL files will be checked every wal_ttl_seconds / 2 and those that
2763    ///    are older than wal_ttl_seconds will be deleted.
2764    /// 4. If both are not 0, WAL files will be checked every 10 min and both
2765    ///    checks will be performed with ttl being first.
2766    ///
2767    /// Default: 0
2768    pub fn set_wal_ttl_seconds(&mut self, secs: u64) {
2769        unsafe {
2770            ffi::rocksdb_options_set_WAL_ttl_seconds(self.inner, secs);
2771        }
2772    }
2773
2774    /// Sets the WAL size limit in MB.
2775    ///
2776    /// If total size of WAL files is greater then wal_size_limit_mb,
2777    /// they will be deleted starting with the earliest until size_limit is met.
2778    ///
2779    /// Default: 0
2780    pub fn set_wal_size_limit_mb(&mut self, size: u64) {
2781        unsafe {
2782            ffi::rocksdb_options_set_WAL_size_limit_MB(self.inner, size);
2783        }
2784    }
2785
2786    /// Sets the number of bytes to preallocate (via fallocate) the manifest files.
2787    ///
2788    /// Default is 4MB, which is reasonable to reduce random IO
2789    /// as well as prevent overallocation for mounts that preallocate
2790    /// large amounts of data (such as xfs's allocsize option).
2791    pub fn set_manifest_preallocation_size(&mut self, size: usize) {
2792        unsafe {
2793            ffi::rocksdb_options_set_manifest_preallocation_size(self.inner, size);
2794        }
2795    }
2796
2797    /// If true, then DB::Open() will not update the statistics used to optimize
2798    /// compaction decision by loading table properties from many files.
2799    /// Turning off this feature will improve DBOpen time especially in disk environment.
2800    ///
2801    /// Default: false
2802    pub fn set_skip_stats_update_on_db_open(&mut self, skip: bool) {
2803        unsafe {
2804            ffi::rocksdb_options_set_skip_stats_update_on_db_open(self.inner, c_uchar::from(skip));
2805        }
2806    }
2807
2808    /// Specify the maximal number of info log files to be kept.
2809    ///
2810    /// Default: 1000
2811    ///
2812    /// # Examples
2813    ///
2814    /// ```
2815    /// use rocksdb::Options;
2816    ///
2817    /// let mut options = Options::default();
2818    /// options.set_keep_log_file_num(100);
2819    /// ```
2820    pub fn set_keep_log_file_num(&mut self, nfiles: usize) {
2821        unsafe {
2822            ffi::rocksdb_options_set_keep_log_file_num(self.inner, nfiles);
2823        }
2824    }
2825
2826    /// Allow the OS to mmap file for writing.
2827    ///
2828    /// Default: false
2829    ///
2830    /// # Examples
2831    ///
2832    /// ```
2833    /// use rocksdb::Options;
2834    ///
2835    /// let mut options = Options::default();
2836    /// options.set_allow_mmap_writes(true);
2837    /// ```
2838    pub fn set_allow_mmap_writes(&mut self, is_enabled: bool) {
2839        unsafe {
2840            ffi::rocksdb_options_set_allow_mmap_writes(self.inner, c_uchar::from(is_enabled));
2841        }
2842    }
2843
2844    /// Allow the OS to mmap file for reading sst tables.
2845    ///
2846    /// Default: false
2847    ///
2848    /// # Examples
2849    ///
2850    /// ```
2851    /// use rocksdb::Options;
2852    ///
2853    /// let mut options = Options::default();
2854    /// options.set_allow_mmap_reads(true);
2855    /// ```
2856    pub fn set_allow_mmap_reads(&mut self, is_enabled: bool) {
2857        unsafe {
2858            ffi::rocksdb_options_set_allow_mmap_reads(self.inner, c_uchar::from(is_enabled));
2859        }
2860    }
2861
2862    /// If enabled, WAL is not flushed automatically after each write. Instead it
2863    /// relies on manual invocation of `DB::flush_wal()` to write the WAL buffer
2864    /// to its file.
2865    ///
2866    /// Default: false
2867    ///
2868    /// # Examples
2869    ///
2870    /// ```
2871    /// use rocksdb::Options;
2872    ///
2873    /// let mut options = Options::default();
2874    /// options.set_manual_wal_flush(true);
2875    /// ```
2876    pub fn set_manual_wal_flush(&mut self, is_enabled: bool) {
2877        unsafe {
2878            ffi::rocksdb_options_set_manual_wal_flush(self.inner, c_uchar::from(is_enabled));
2879        }
2880    }
2881
2882    /// Guarantee that all column families are flushed together atomically.
2883    /// This option applies to both manual flushes (`db.flush()`) and automatic
2884    /// background flushes caused when memtables are filled.
2885    ///
2886    /// Note that this is only useful when the WAL is disabled. When using the
2887    /// WAL, writes are always consistent across column families.
2888    ///
2889    /// Default: false
2890    ///
2891    /// # Examples
2892    ///
2893    /// ```
2894    /// use rocksdb::Options;
2895    ///
2896    /// let mut options = Options::default();
2897    /// options.set_atomic_flush(true);
2898    /// ```
2899    pub fn set_atomic_flush(&mut self, atomic_flush: bool) {
2900        unsafe {
2901            ffi::rocksdb_options_set_atomic_flush(self.inner, c_uchar::from(atomic_flush));
2902        }
2903    }
2904
2905    /// Sets global cache for table-level rows. Cache must outlive DB instance which uses it.
2906    ///
2907    /// Default: null (disabled)
2908    /// Not supported in ROCKSDB_LITE mode!
2909    pub fn set_row_cache(&mut self, cache: &Cache) {
2910        unsafe {
2911            ffi::rocksdb_options_set_row_cache(self.inner, cache.0.inner);
2912        }
2913        self.outlive.row_cache = Some(cache.clone());
2914    }
2915
2916    /// Use to control write rate of flush and compaction. Flush has higher
2917    /// priority than compaction.
2918    /// If rate limiter is enabled, bytes_per_sync is set to 1MB by default.
2919    ///
2920    /// Default: disable
2921    ///
2922    /// # Examples
2923    ///
2924    /// ```
2925    /// use rocksdb::Options;
2926    ///
2927    /// let mut options = Options::default();
2928    /// options.set_ratelimiter(1024 * 1024, 100 * 1000, 10);
2929    /// ```
2930    pub fn set_ratelimiter(
2931        &mut self,
2932        rate_bytes_per_sec: i64,
2933        refill_period_us: i64,
2934        fairness: i32,
2935    ) {
2936        unsafe {
2937            let ratelimiter =
2938                ffi::rocksdb_ratelimiter_create(rate_bytes_per_sec, refill_period_us, fairness);
2939            // Since limiter is wrapped in shared_ptr, we don't need to
2940            // call rocksdb_ratelimiter_destroy explicitly.
2941            ffi::rocksdb_options_set_ratelimiter(self.inner, ratelimiter);
2942        }
2943    }
2944
2945    /// Sets the maximal size of the info log file.
2946    ///
2947    /// If the log file is larger than `max_log_file_size`, a new info log file
2948    /// will be created. If `max_log_file_size` is equal to zero, all logs will
2949    /// be written to one log file.
2950    ///
2951    /// Default: 0
2952    ///
2953    /// # Examples
2954    ///
2955    /// ```
2956    /// use rocksdb::Options;
2957    ///
2958    /// let mut options = Options::default();
2959    /// options.set_max_log_file_size(0);
2960    /// ```
2961    pub fn set_max_log_file_size(&mut self, size: usize) {
2962        unsafe {
2963            ffi::rocksdb_options_set_max_log_file_size(self.inner, size);
2964        }
2965    }
2966
2967    /// Sets the time for the info log file to roll (in seconds).
2968    ///
2969    /// If specified with non-zero value, log file will be rolled
2970    /// if it has been active longer than `log_file_time_to_roll`.
2971    /// Default: 0 (disabled)
2972    pub fn set_log_file_time_to_roll(&mut self, secs: usize) {
2973        unsafe {
2974            ffi::rocksdb_options_set_log_file_time_to_roll(self.inner, secs);
2975        }
2976    }
2977
2978    /// Controls the recycling of log files.
2979    ///
2980    /// If non-zero, previously written log files will be reused for new logs,
2981    /// overwriting the old data. The value indicates how many such files we will
2982    /// keep around at any point in time for later use. This is more efficient
2983    /// because the blocks are already allocated and fdatasync does not need to
2984    /// update the inode after each write.
2985    ///
2986    /// Default: 0
2987    ///
2988    /// # Examples
2989    ///
2990    /// ```
2991    /// use rocksdb::Options;
2992    ///
2993    /// let mut options = Options::default();
2994    /// options.set_recycle_log_file_num(5);
2995    /// ```
2996    pub fn set_recycle_log_file_num(&mut self, num: usize) {
2997        unsafe {
2998            ffi::rocksdb_options_set_recycle_log_file_num(self.inner, num);
2999        }
3000    }
3001
3002    /// Sets the threshold at which all writes will be slowed down to at least delayed_write_rate if estimated
3003    /// bytes needed to be compaction exceed this threshold.
3004    ///
3005    /// Default: 64GB
3006    pub fn set_soft_pending_compaction_bytes_limit(&mut self, limit: usize) {
3007        unsafe {
3008            ffi::rocksdb_options_set_soft_pending_compaction_bytes_limit(self.inner, limit);
3009        }
3010    }
3011
3012    /// Sets the bytes threshold at which all writes are stopped if estimated bytes needed to be compaction exceed
3013    /// this threshold.
3014    ///
3015    /// Default: 256GB
3016    pub fn set_hard_pending_compaction_bytes_limit(&mut self, limit: usize) {
3017        unsafe {
3018            ffi::rocksdb_options_set_hard_pending_compaction_bytes_limit(self.inner, limit);
3019        }
3020    }
3021
3022    /// Sets the size of one block in arena memory allocation.
3023    ///
3024    /// If <= 0, a proper value is automatically calculated (usually 1/10 of
3025    /// writer_buffer_size).
3026    ///
3027    /// Default: 0
3028    pub fn set_arena_block_size(&mut self, size: usize) {
3029        unsafe {
3030            ffi::rocksdb_options_set_arena_block_size(self.inner, size);
3031        }
3032    }
3033
3034    /// If true, then print malloc stats together with rocksdb.stats when printing to LOG.
3035    ///
3036    /// Default: false
3037    pub fn set_dump_malloc_stats(&mut self, enabled: bool) {
3038        unsafe {
3039            ffi::rocksdb_options_set_dump_malloc_stats(self.inner, c_uchar::from(enabled));
3040        }
3041    }
3042
3043    /// Enable whole key bloom filter in memtable. Note this will only take effect
3044    /// if memtable_prefix_bloom_size_ratio is not 0. Enabling whole key filtering
3045    /// can potentially reduce CPU usage for point-look-ups.
3046    ///
3047    /// Default: false (disable)
3048    ///
3049    /// Dynamically changeable through SetOptions() API
3050    pub fn set_memtable_whole_key_filtering(&mut self, whole_key_filter: bool) {
3051        unsafe {
3052            ffi::rocksdb_options_set_memtable_whole_key_filtering(
3053                self.inner,
3054                c_uchar::from(whole_key_filter),
3055            );
3056        }
3057    }
3058
3059    /// Enable the use of key-value separation.
3060    ///
3061    /// More details can be found here: http://rocksdb.org/blog/2021/05/26/integrated-blob-db.html.
3062    ///
3063    /// Default: false (disable)
3064    ///
3065    /// Dynamically changeable through SetOptions() API
3066    pub fn set_enable_blob_files(&mut self, val: bool) {
3067        unsafe {
3068            ffi::rocksdb_options_set_enable_blob_files(self.inner, u8::from(val));
3069        }
3070    }
3071
3072    /// Sets the minimum threshold value at or above which will be written
3073    /// to blob files during flush or compaction.
3074    ///
3075    /// Dynamically changeable through SetOptions() API
3076    pub fn set_min_blob_size(&mut self, val: u64) {
3077        unsafe {
3078            ffi::rocksdb_options_set_min_blob_size(self.inner, val);
3079        }
3080    }
3081
3082    /// Sets the size limit for blob files.
3083    ///
3084    /// Dynamically changeable through SetOptions() API
3085    pub fn set_blob_file_size(&mut self, val: u64) {
3086        unsafe {
3087            ffi::rocksdb_options_set_blob_file_size(self.inner, val);
3088        }
3089    }
3090
3091    /// Sets the blob compression type. All blob files use the same
3092    /// compression type.
3093    ///
3094    /// Dynamically changeable through SetOptions() API
3095    pub fn set_blob_compression_type(&mut self, val: DBCompressionType) {
3096        unsafe {
3097            ffi::rocksdb_options_set_blob_compression_type(self.inner, val as _);
3098        }
3099    }
3100
3101    /// If this is set to true RocksDB will actively relocate valid blobs from the oldest blob files
3102    /// as they are encountered during compaction.
3103    ///
3104    /// Dynamically changeable through SetOptions() API
3105    pub fn set_enable_blob_gc(&mut self, val: bool) {
3106        unsafe {
3107            ffi::rocksdb_options_set_enable_blob_gc(self.inner, u8::from(val));
3108        }
3109    }
3110
3111    /// Sets the threshold that the GC logic uses to determine which blob files should be considered “old.”
3112    ///
3113    /// For example, the default value of 0.25 signals to RocksDB that blobs residing in the
3114    /// oldest 25% of blob files should be relocated by GC. This parameter can be tuned to adjust
3115    /// the trade-off between write amplification and space amplification.
3116    ///
3117    /// Dynamically changeable through SetOptions() API
3118    pub fn set_blob_gc_age_cutoff(&mut self, val: c_double) {
3119        unsafe {
3120            ffi::rocksdb_options_set_blob_gc_age_cutoff(self.inner, val);
3121        }
3122    }
3123
3124    /// Sets the blob GC force threshold.
3125    ///
3126    /// Dynamically changeable through SetOptions() API
3127    pub fn set_blob_gc_force_threshold(&mut self, val: c_double) {
3128        unsafe {
3129            ffi::rocksdb_options_set_blob_gc_force_threshold(self.inner, val);
3130        }
3131    }
3132
3133    /// Sets the blob compaction read ahead size.
3134    ///
3135    /// Dynamically changeable through SetOptions() API
3136    pub fn set_blob_compaction_readahead_size(&mut self, val: u64) {
3137        unsafe {
3138            ffi::rocksdb_options_set_blob_compaction_readahead_size(self.inner, val);
3139        }
3140    }
3141}
3142
3143impl Default for Options {
3144    fn default() -> Self {
3145        unsafe {
3146            let opts = ffi::rocksdb_options_create();
3147            assert!(!opts.is_null(), "Could not create RocksDB options");
3148
3149            Self {
3150                inner: opts,
3151                outlive: OptionsMustOutliveDB::default(),
3152            }
3153        }
3154    }
3155}
3156
3157impl FlushOptions {
3158    pub fn new() -> FlushOptions {
3159        FlushOptions::default()
3160    }
3161
3162    /// Waits until the flush is done.
3163    ///
3164    /// Default: true
3165    ///
3166    /// # Examples
3167    ///
3168    /// ```
3169    /// use rocksdb::FlushOptions;
3170    ///
3171    /// let mut options = FlushOptions::default();
3172    /// options.set_wait(false);
3173    /// ```
3174    pub fn set_wait(&mut self, wait: bool) {
3175        unsafe {
3176            ffi::rocksdb_flushoptions_set_wait(self.inner, c_uchar::from(wait));
3177        }
3178    }
3179}
3180
3181impl Default for FlushOptions {
3182    fn default() -> Self {
3183        let flush_opts = unsafe { ffi::rocksdb_flushoptions_create() };
3184        assert!(
3185            !flush_opts.is_null(),
3186            "Could not create RocksDB flush options"
3187        );
3188
3189        Self { inner: flush_opts }
3190    }
3191}
3192
3193impl WriteOptions {
3194    pub fn new() -> WriteOptions {
3195        WriteOptions::default()
3196    }
3197
3198    /// Sets the sync mode. If true, the write will be flushed
3199    /// from the operating system buffer cache before the write is considered complete.
3200    /// If this flag is true, writes will be slower.
3201    ///
3202    /// Default: false
3203    pub fn set_sync(&mut self, sync: bool) {
3204        unsafe {
3205            ffi::rocksdb_writeoptions_set_sync(self.inner, c_uchar::from(sync));
3206        }
3207    }
3208
3209    /// Sets whether WAL should be active or not.
3210    /// If true, writes will not first go to the write ahead log,
3211    /// and the write may got lost after a crash.
3212    ///
3213    /// Default: false
3214    pub fn disable_wal(&mut self, disable: bool) {
3215        unsafe {
3216            ffi::rocksdb_writeoptions_disable_WAL(self.inner, c_int::from(disable));
3217        }
3218    }
3219
3220    /// If true and if user is trying to write to column families that don't exist (they were dropped),
3221    /// ignore the write (don't return an error). If there are multiple writes in a WriteBatch,
3222    /// other writes will succeed.
3223    ///
3224    /// Default: false
3225    pub fn set_ignore_missing_column_families(&mut self, ignore: bool) {
3226        unsafe {
3227            ffi::rocksdb_writeoptions_set_ignore_missing_column_families(
3228                self.inner,
3229                c_uchar::from(ignore),
3230            );
3231        }
3232    }
3233
3234    /// If true and we need to wait or sleep for the write request, fails
3235    /// immediately with Status::Incomplete().
3236    ///
3237    /// Default: false
3238    pub fn set_no_slowdown(&mut self, no_slowdown: bool) {
3239        unsafe {
3240            ffi::rocksdb_writeoptions_set_no_slowdown(self.inner, c_uchar::from(no_slowdown));
3241        }
3242    }
3243
3244    /// If true, this write request is of lower priority if compaction is
3245    /// behind. In this case, no_slowdown = true, the request will be cancelled
3246    /// immediately with Status::Incomplete() returned. Otherwise, it will be
3247    /// slowed down. The slowdown value is determined by RocksDB to guarantee
3248    /// it introduces minimum impacts to high priority writes.
3249    ///
3250    /// Default: false
3251    pub fn set_low_pri(&mut self, v: bool) {
3252        unsafe {
3253            ffi::rocksdb_writeoptions_set_low_pri(self.inner, c_uchar::from(v));
3254        }
3255    }
3256
3257    /// If true, writebatch will maintain the last insert positions of each
3258    /// memtable as hints in concurrent write. It can improve write performance
3259    /// in concurrent writes if keys in one writebatch are sequential. In
3260    /// non-concurrent writes (when concurrent_memtable_writes is false) this
3261    /// option will be ignored.
3262    ///
3263    /// Default: false
3264    pub fn set_memtable_insert_hint_per_batch(&mut self, v: bool) {
3265        unsafe {
3266            ffi::rocksdb_writeoptions_set_memtable_insert_hint_per_batch(
3267                self.inner,
3268                c_uchar::from(v),
3269            );
3270        }
3271    }
3272}
3273
3274impl Default for WriteOptions {
3275    fn default() -> Self {
3276        let write_opts = unsafe { ffi::rocksdb_writeoptions_create() };
3277        assert!(
3278            !write_opts.is_null(),
3279            "Could not create RocksDB write options"
3280        );
3281
3282        Self { inner: write_opts }
3283    }
3284}
3285
3286#[derive(Debug, Copy, Clone, PartialEq, Eq)]
3287#[cfg_attr(feature = "serde1", derive(serde::Serialize, serde::Deserialize))]
3288#[repr(i32)]
3289pub enum ReadTier {
3290    /// Reads data in memtable, block cache, OS cache or storage.
3291    All = 0,
3292    /// Reads data in memtable or block cache.
3293    BlockCache,
3294}
3295
3296impl ReadOptions {
3297    // TODO add snapshot setting here
3298    // TODO add snapshot wrapper structs with proper destructors;
3299    // that struct needs an "iterator" impl too.
3300
3301    /// Specify whether the "data block"/"index block"/"filter block"
3302    /// read for this iteration should be cached in memory?
3303    /// Callers may wish to set this field to false for bulk scans.
3304    ///
3305    /// Default: true
3306    pub fn fill_cache(&mut self, v: bool) {
3307        unsafe {
3308            ffi::rocksdb_readoptions_set_fill_cache(self.inner, c_uchar::from(v));
3309        }
3310    }
3311
3312    /// Sets the snapshot which should be used for the read.
3313    /// The snapshot must belong to the DB that is being read and must
3314    /// not have been released.
3315    pub(crate) fn set_snapshot<D: DBAccess>(&mut self, snapshot: &SnapshotWithThreadMode<D>) {
3316        unsafe {
3317            ffi::rocksdb_readoptions_set_snapshot(self.inner, snapshot.inner);
3318        }
3319    }
3320
3321    /// Sets the lower bound for an iterator.
3322    pub fn set_iterate_lower_bound<K: Into<Vec<u8>>>(&mut self, key: K) {
3323        self.set_lower_bound_impl(Some(key.into()));
3324    }
3325
3326    /// Sets the upper bound for an iterator.
3327    /// The upper bound itself is not included on the iteration result.
3328    pub fn set_iterate_upper_bound<K: Into<Vec<u8>>>(&mut self, key: K) {
3329        self.set_upper_bound_impl(Some(key.into()));
3330    }
3331
3332    /// Sets lower and upper bounds based on the provided range.  This is
3333    /// similar to setting lower and upper bounds separately except that it also
3334    /// allows either bound to be reset.
3335    ///
3336    /// The argument can be a regular Rust range, e.g. `lower..upper`.  However,
3337    /// since RocksDB upper bound is always excluded (i.e. range can never be
3338    /// fully closed) inclusive ranges (`lower..=upper` and `..=upper`) are not
3339    /// supported.  For example:
3340    ///
3341    /// ```
3342    /// let mut options = rocksdb::ReadOptions::default();
3343    /// options.set_iterate_range("xy".as_bytes().."xz".as_bytes());
3344    /// ```
3345    ///
3346    /// In addition, [`crate::PrefixRange`] can be used to specify a range of
3347    /// keys with a given prefix.  In particular, the above example is
3348    /// equivalent to:
3349    ///
3350    /// ```
3351    /// let mut options = rocksdb::ReadOptions::default();
3352    /// options.set_iterate_range(rocksdb::PrefixRange("xy".as_bytes()));
3353    /// ```
3354    ///
3355    /// Note that setting range using this method is separate to using prefix
3356    /// iterators.  Prefix iterators use prefix extractor configured for
3357    /// a column family.  Setting bounds via [`crate::PrefixRange`] is more akin
3358    /// to using manual prefix.
3359    ///
3360    /// Using this method clears any previously set bounds.  In other words, the
3361    /// bounds can be reset by setting the range to `..` as in:
3362    ///
3363    /// ```
3364    /// let mut options = rocksdb::ReadOptions::default();
3365    /// options.set_iterate_range(..);
3366    /// ```
3367    pub fn set_iterate_range(&mut self, range: impl crate::IterateBounds) {
3368        let (lower, upper) = range.into_bounds();
3369        self.set_lower_bound_impl(lower);
3370        self.set_upper_bound_impl(upper);
3371    }
3372
3373    fn set_lower_bound_impl(&mut self, bound: Option<Vec<u8>>) {
3374        let (ptr, len) = if let Some(ref bound) = bound {
3375            (bound.as_ptr() as *const c_char, bound.len())
3376        } else if self.iterate_lower_bound.is_some() {
3377            (std::ptr::null(), 0)
3378        } else {
3379            return;
3380        };
3381        self.iterate_lower_bound = bound;
3382        unsafe {
3383            ffi::rocksdb_readoptions_set_iterate_lower_bound(self.inner, ptr, len);
3384        }
3385    }
3386
3387    fn set_upper_bound_impl(&mut self, bound: Option<Vec<u8>>) {
3388        let (ptr, len) = if let Some(ref bound) = bound {
3389            (bound.as_ptr() as *const c_char, bound.len())
3390        } else if self.iterate_upper_bound.is_some() {
3391            (std::ptr::null(), 0)
3392        } else {
3393            return;
3394        };
3395        self.iterate_upper_bound = bound;
3396        unsafe {
3397            ffi::rocksdb_readoptions_set_iterate_upper_bound(self.inner, ptr, len);
3398        }
3399    }
3400
3401    /// Specify if this read request should process data that ALREADY
3402    /// resides on a particular cache. If the required data is not
3403    /// found at the specified cache, then Status::Incomplete is returned.
3404    ///
3405    /// Default: ::All
3406    pub fn set_read_tier(&mut self, tier: ReadTier) {
3407        unsafe {
3408            ffi::rocksdb_readoptions_set_read_tier(self.inner, tier as c_int);
3409        }
3410    }
3411
3412    /// Enforce that the iterator only iterates over the same
3413    /// prefix as the seek.
3414    /// This option is effective only for prefix seeks, i.e. prefix_extractor is
3415    /// non-null for the column family and total_order_seek is false.  Unlike
3416    /// iterate_upper_bound, prefix_same_as_start only works within a prefix
3417    /// but in both directions.
3418    ///
3419    /// Default: false
3420    pub fn set_prefix_same_as_start(&mut self, v: bool) {
3421        unsafe {
3422            ffi::rocksdb_readoptions_set_prefix_same_as_start(self.inner, c_uchar::from(v));
3423        }
3424    }
3425
3426    /// Enable a total order seek regardless of index format (e.g. hash index)
3427    /// used in the table. Some table format (e.g. plain table) may not support
3428    /// this option.
3429    ///
3430    /// If true when calling Get(), we also skip prefix bloom when reading from
3431    /// block based table. It provides a way to read existing data after
3432    /// changing implementation of prefix extractor.
3433    pub fn set_total_order_seek(&mut self, v: bool) {
3434        unsafe {
3435            ffi::rocksdb_readoptions_set_total_order_seek(self.inner, c_uchar::from(v));
3436        }
3437    }
3438
3439    /// Sets a threshold for the number of keys that can be skipped
3440    /// before failing an iterator seek as incomplete. The default value of 0 should be used to
3441    /// never fail a request as incomplete, even on skipping too many keys.
3442    ///
3443    /// Default: 0
3444    pub fn set_max_skippable_internal_keys(&mut self, num: u64) {
3445        unsafe {
3446            ffi::rocksdb_readoptions_set_max_skippable_internal_keys(self.inner, num);
3447        }
3448    }
3449
3450    /// If true, when PurgeObsoleteFile is called in CleanupIteratorState, we schedule a background job
3451    /// in the flush job queue and delete obsolete files in background.
3452    ///
3453    /// Default: false
3454    pub fn set_background_purge_on_iterator_cleanup(&mut self, v: bool) {
3455        unsafe {
3456            ffi::rocksdb_readoptions_set_background_purge_on_iterator_cleanup(
3457                self.inner,
3458                c_uchar::from(v),
3459            );
3460        }
3461    }
3462
3463    /// If true, keys deleted using the DeleteRange() API will be visible to
3464    /// readers until they are naturally deleted during compaction. This improves
3465    /// read performance in DBs with many range deletions.
3466    ///
3467    /// Default: false
3468    pub fn set_ignore_range_deletions(&mut self, v: bool) {
3469        unsafe {
3470            ffi::rocksdb_readoptions_set_ignore_range_deletions(self.inner, c_uchar::from(v));
3471        }
3472    }
3473
3474    /// If true, all data read from underlying storage will be
3475    /// verified against corresponding checksums.
3476    ///
3477    /// Default: true
3478    pub fn set_verify_checksums(&mut self, v: bool) {
3479        unsafe {
3480            ffi::rocksdb_readoptions_set_verify_checksums(self.inner, c_uchar::from(v));
3481        }
3482    }
3483
3484    /// If non-zero, an iterator will create a new table reader which
3485    /// performs reads of the given size. Using a large size (> 2MB) can
3486    /// improve the performance of forward iteration on spinning disks.
3487    /// Default: 0
3488    ///
3489    /// ```
3490    /// use rocksdb::{ReadOptions};
3491    ///
3492    /// let mut opts = ReadOptions::default();
3493    /// opts.set_readahead_size(4_194_304); // 4mb
3494    /// ```
3495    pub fn set_readahead_size(&mut self, v: usize) {
3496        unsafe {
3497            ffi::rocksdb_readoptions_set_readahead_size(self.inner, v as size_t);
3498        }
3499    }
3500
3501    /// If true, create a tailing iterator. Note that tailing iterators
3502    /// only support moving in the forward direction. Iterating in reverse
3503    /// or seek_to_last are not supported.
3504    pub fn set_tailing(&mut self, v: bool) {
3505        unsafe {
3506            ffi::rocksdb_readoptions_set_tailing(self.inner, c_uchar::from(v));
3507        }
3508    }
3509
3510    /// Specifies the value of "pin_data". If true, it keeps the blocks
3511    /// loaded by the iterator pinned in memory as long as the iterator is not deleted,
3512    /// If used when reading from tables created with
3513    /// BlockBasedTableOptions::use_delta_encoding = false,
3514    /// Iterator's property "rocksdb.iterator.is-key-pinned" is guaranteed to
3515    /// return 1.
3516    ///
3517    /// Default: false
3518    pub fn set_pin_data(&mut self, v: bool) {
3519        unsafe {
3520            ffi::rocksdb_readoptions_set_pin_data(self.inner, c_uchar::from(v));
3521        }
3522    }
3523}
3524
3525impl Default for ReadOptions {
3526    fn default() -> Self {
3527        unsafe {
3528            Self {
3529                inner: ffi::rocksdb_readoptions_create(),
3530                iterate_upper_bound: None,
3531                iterate_lower_bound: None,
3532            }
3533        }
3534    }
3535}
3536
3537impl IngestExternalFileOptions {
3538    /// Can be set to true to move the files instead of copying them.
3539    pub fn set_move_files(&mut self, v: bool) {
3540        unsafe {
3541            ffi::rocksdb_ingestexternalfileoptions_set_move_files(self.inner, c_uchar::from(v));
3542        }
3543    }
3544
3545    /// If set to false, an ingested file keys could appear in existing snapshots
3546    /// that where created before the file was ingested.
3547    pub fn set_snapshot_consistency(&mut self, v: bool) {
3548        unsafe {
3549            ffi::rocksdb_ingestexternalfileoptions_set_snapshot_consistency(
3550                self.inner,
3551                c_uchar::from(v),
3552            );
3553        }
3554    }
3555
3556    /// If set to false, IngestExternalFile() will fail if the file key range
3557    /// overlaps with existing keys or tombstones in the DB.
3558    pub fn set_allow_global_seqno(&mut self, v: bool) {
3559        unsafe {
3560            ffi::rocksdb_ingestexternalfileoptions_set_allow_global_seqno(
3561                self.inner,
3562                c_uchar::from(v),
3563            );
3564        }
3565    }
3566
3567    /// If set to false and the file key range overlaps with the memtable key range
3568    /// (memtable flush required), IngestExternalFile will fail.
3569    pub fn set_allow_blocking_flush(&mut self, v: bool) {
3570        unsafe {
3571            ffi::rocksdb_ingestexternalfileoptions_set_allow_blocking_flush(
3572                self.inner,
3573                c_uchar::from(v),
3574            );
3575        }
3576    }
3577
3578    /// Set to true if you would like duplicate keys in the file being ingested
3579    /// to be skipped rather than overwriting existing data under that key.
3580    /// Usecase: back-fill of some historical data in the database without
3581    /// over-writing existing newer version of data.
3582    /// This option could only be used if the DB has been running
3583    /// with allow_ingest_behind=true since the dawn of time.
3584    /// All files will be ingested at the bottommost level with seqno=0.
3585    pub fn set_ingest_behind(&mut self, v: bool) {
3586        unsafe {
3587            ffi::rocksdb_ingestexternalfileoptions_set_ingest_behind(self.inner, c_uchar::from(v));
3588        }
3589    }
3590}
3591
3592impl Default for IngestExternalFileOptions {
3593    fn default() -> Self {
3594        unsafe {
3595            Self {
3596                inner: ffi::rocksdb_ingestexternalfileoptions_create(),
3597            }
3598        }
3599    }
3600}
3601
3602/// Used by BlockBasedOptions::set_index_type.
3603pub enum BlockBasedIndexType {
3604    /// A space efficient index block that is optimized for
3605    /// binary-search-based index.
3606    BinarySearch,
3607
3608    /// The hash index, if enabled, will perform a hash lookup if
3609    /// a prefix extractor has been provided through Options::set_prefix_extractor.
3610    HashSearch,
3611
3612    /// A two-level index implementation. Both levels are binary search indexes.
3613    TwoLevelIndexSearch,
3614}
3615
3616/// Used by BlockBasedOptions::set_data_block_index_type.
3617#[repr(C)]
3618pub enum DataBlockIndexType {
3619    /// Use binary search when performing point lookup for keys in data blocks.
3620    /// This is the default.
3621    BinarySearch = 0,
3622
3623    /// Appends a compact hash table to the end of the data block for efficient indexing. Backwards
3624    /// compatible with databases created without this feature. Once turned on, existing data will
3625    /// be gradually converted to the hash index format.
3626    BinaryAndHash = 1,
3627}
3628
3629/// Defines the underlying memtable implementation.
3630/// See official [wiki](https://github.com/facebook/rocksdb/wiki/MemTable) for more information.
3631pub enum MemtableFactory {
3632    Vector,
3633    HashSkipList {
3634        bucket_count: usize,
3635        height: i32,
3636        branching_factor: i32,
3637    },
3638    HashLinkList {
3639        bucket_count: usize,
3640    },
3641}
3642
3643/// Used by BlockBasedOptions::set_checksum_type.
3644pub enum ChecksumType {
3645    NoChecksum = 0,
3646    CRC32c = 1,
3647    XXHash = 2,
3648    XXHash64 = 3,
3649    XXH3 = 4, // Supported since RocksDB 6.27
3650}
3651
3652/// Used with DBOptions::set_plain_table_factory.
3653/// See official [wiki](https://github.com/facebook/rocksdb/wiki/PlainTable-Format) for more
3654/// information.
3655///
3656/// Defaults:
3657///  user_key_length: 0 (variable length)
3658///  bloom_bits_per_key: 10
3659///  hash_table_ratio: 0.75
3660///  index_sparseness: 16
3661pub struct PlainTableFactoryOptions {
3662    pub user_key_length: u32,
3663    pub bloom_bits_per_key: i32,
3664    pub hash_table_ratio: f64,
3665    pub index_sparseness: usize,
3666}
3667
3668#[derive(Debug, Copy, Clone, PartialEq, Eq)]
3669#[cfg_attr(feature = "serde1", derive(serde::Serialize, serde::Deserialize))]
3670pub enum DBCompressionType {
3671    None = ffi::rocksdb_no_compression as isize,
3672    Snappy = ffi::rocksdb_snappy_compression as isize,
3673    Zlib = ffi::rocksdb_zlib_compression as isize,
3674    Bz2 = ffi::rocksdb_bz2_compression as isize,
3675    Lz4 = ffi::rocksdb_lz4_compression as isize,
3676    Lz4hc = ffi::rocksdb_lz4hc_compression as isize,
3677    Zstd = ffi::rocksdb_zstd_compression as isize,
3678}
3679
3680#[derive(Debug, Copy, Clone, PartialEq, Eq)]
3681#[cfg_attr(feature = "serde1", derive(serde::Serialize, serde::Deserialize))]
3682pub enum DBCompactionStyle {
3683    Level = ffi::rocksdb_level_compaction as isize,
3684    Universal = ffi::rocksdb_universal_compaction as isize,
3685    Fifo = ffi::rocksdb_fifo_compaction as isize,
3686}
3687
3688#[derive(Debug, Copy, Clone, PartialEq, Eq)]
3689#[cfg_attr(feature = "serde1", derive(serde::Serialize, serde::Deserialize))]
3690pub enum DBRecoveryMode {
3691    TolerateCorruptedTailRecords = ffi::rocksdb_tolerate_corrupted_tail_records_recovery as isize,
3692    AbsoluteConsistency = ffi::rocksdb_absolute_consistency_recovery as isize,
3693    PointInTime = ffi::rocksdb_point_in_time_recovery as isize,
3694    SkipAnyCorruptedRecord = ffi::rocksdb_skip_any_corrupted_records_recovery as isize,
3695}
3696
3697/// File access pattern once a compaction has started
3698#[derive(Debug, Copy, Clone, PartialEq, Eq)]
3699#[cfg_attr(feature = "serde1", derive(serde::Serialize, serde::Deserialize))]
3700#[repr(i32)]
3701pub enum AccessHint {
3702    None = 0,
3703    Normal,
3704    Sequential,
3705    WillNeed,
3706}
3707
3708pub struct FifoCompactOptions {
3709    pub(crate) inner: *mut ffi::rocksdb_fifo_compaction_options_t,
3710}
3711
3712impl Default for FifoCompactOptions {
3713    fn default() -> Self {
3714        let opts = unsafe { ffi::rocksdb_fifo_compaction_options_create() };
3715        assert!(
3716            !opts.is_null(),
3717            "Could not create RocksDB Fifo Compaction Options"
3718        );
3719
3720        Self { inner: opts }
3721    }
3722}
3723
3724impl Drop for FifoCompactOptions {
3725    fn drop(&mut self) {
3726        unsafe {
3727            ffi::rocksdb_fifo_compaction_options_destroy(self.inner);
3728        }
3729    }
3730}
3731
3732impl FifoCompactOptions {
3733    /// Sets the max table file size.
3734    ///
3735    /// Once the total sum of table files reaches this, we will delete the oldest
3736    /// table file
3737    ///
3738    /// Default: 1GB
3739    pub fn set_max_table_files_size(&mut self, nbytes: u64) {
3740        unsafe {
3741            ffi::rocksdb_fifo_compaction_options_set_max_table_files_size(self.inner, nbytes);
3742        }
3743    }
3744}
3745
3746#[derive(Debug, Copy, Clone, PartialEq, Eq)]
3747#[cfg_attr(feature = "serde1", derive(serde::Serialize, serde::Deserialize))]
3748pub enum UniversalCompactionStopStyle {
3749    Similar = ffi::rocksdb_similar_size_compaction_stop_style as isize,
3750    Total = ffi::rocksdb_total_size_compaction_stop_style as isize,
3751}
3752
3753pub struct UniversalCompactOptions {
3754    pub(crate) inner: *mut ffi::rocksdb_universal_compaction_options_t,
3755}
3756
3757impl Default for UniversalCompactOptions {
3758    fn default() -> Self {
3759        let opts = unsafe { ffi::rocksdb_universal_compaction_options_create() };
3760        assert!(
3761            !opts.is_null(),
3762            "Could not create RocksDB Universal Compaction Options"
3763        );
3764
3765        Self { inner: opts }
3766    }
3767}
3768
3769impl Drop for UniversalCompactOptions {
3770    fn drop(&mut self) {
3771        unsafe {
3772            ffi::rocksdb_universal_compaction_options_destroy(self.inner);
3773        }
3774    }
3775}
3776
3777impl UniversalCompactOptions {
3778    /// Sets the percentage flexibility while comparing file size.
3779    /// If the candidate file(s) size is 1% smaller than the next file's size,
3780    /// then include next file into this candidate set.
3781    ///
3782    /// Default: 1
3783    pub fn set_size_ratio(&mut self, ratio: c_int) {
3784        unsafe {
3785            ffi::rocksdb_universal_compaction_options_set_size_ratio(self.inner, ratio);
3786        }
3787    }
3788
3789    /// Sets the minimum number of files in a single compaction run.
3790    ///
3791    /// Default: 2
3792    pub fn set_min_merge_width(&mut self, num: c_int) {
3793        unsafe {
3794            ffi::rocksdb_universal_compaction_options_set_min_merge_width(self.inner, num);
3795        }
3796    }
3797
3798    /// Sets the maximum number of files in a single compaction run.
3799    ///
3800    /// Default: UINT_MAX
3801    pub fn set_max_merge_width(&mut self, num: c_int) {
3802        unsafe {
3803            ffi::rocksdb_universal_compaction_options_set_max_merge_width(self.inner, num);
3804        }
3805    }
3806
3807    /// sets the size amplification.
3808    ///
3809    /// It is defined as the amount (in percentage) of
3810    /// additional storage needed to store a single byte of data in the database.
3811    /// For example, a size amplification of 2% means that a database that
3812    /// contains 100 bytes of user-data may occupy upto 102 bytes of
3813    /// physical storage. By this definition, a fully compacted database has
3814    /// a size amplification of 0%. Rocksdb uses the following heuristic
3815    /// to calculate size amplification: it assumes that all files excluding
3816    /// the earliest file contribute to the size amplification.
3817    ///
3818    /// Default: 200, which means that a 100 byte database could require upto 300 bytes of storage.
3819    pub fn set_max_size_amplification_percent(&mut self, v: c_int) {
3820        unsafe {
3821            ffi::rocksdb_universal_compaction_options_set_max_size_amplification_percent(
3822                self.inner, v,
3823            );
3824        }
3825    }
3826
3827    /// Sets the percentage of compression size.
3828    ///
3829    /// If this option is set to be -1, all the output files
3830    /// will follow compression type specified.
3831    ///
3832    /// If this option is not negative, we will try to make sure compressed
3833    /// size is just above this value. In normal cases, at least this percentage
3834    /// of data will be compressed.
3835    /// When we are compacting to a new file, here is the criteria whether
3836    /// it needs to be compressed: assuming here are the list of files sorted
3837    /// by generation time:
3838    ///    A1...An B1...Bm C1...Ct
3839    /// where A1 is the newest and Ct is the oldest, and we are going to compact
3840    /// B1...Bm, we calculate the total size of all the files as total_size, as
3841    /// well as  the total size of C1...Ct as total_C, the compaction output file
3842    /// will be compressed iff
3843    ///   total_C / total_size < this percentage
3844    ///
3845    /// Default: -1
3846    pub fn set_compression_size_percent(&mut self, v: c_int) {
3847        unsafe {
3848            ffi::rocksdb_universal_compaction_options_set_compression_size_percent(self.inner, v);
3849        }
3850    }
3851
3852    /// Sets the algorithm used to stop picking files into a single compaction run.
3853    ///
3854    /// Default: ::Total
3855    pub fn set_stop_style(&mut self, style: UniversalCompactionStopStyle) {
3856        unsafe {
3857            ffi::rocksdb_universal_compaction_options_set_stop_style(self.inner, style as c_int);
3858        }
3859    }
3860}
3861
3862#[derive(Debug, Copy, Clone, PartialEq, Eq)]
3863#[cfg_attr(feature = "serde1", derive(serde::Serialize, serde::Deserialize))]
3864#[repr(u8)]
3865pub enum BottommostLevelCompaction {
3866    /// Skip bottommost level compaction
3867    Skip = 0,
3868    /// Only compact bottommost level if there is a compaction filter
3869    /// This is the default option
3870    IfHaveCompactionFilter,
3871    /// Always compact bottommost level
3872    Force,
3873    /// Always compact bottommost level but in bottommost level avoid
3874    /// double-compacting files created in the same compaction
3875    ForceOptimized,
3876}
3877
3878pub struct CompactOptions {
3879    pub(crate) inner: *mut ffi::rocksdb_compactoptions_t,
3880}
3881
3882impl Default for CompactOptions {
3883    fn default() -> Self {
3884        let opts = unsafe { ffi::rocksdb_compactoptions_create() };
3885        assert!(!opts.is_null(), "Could not create RocksDB Compact Options");
3886
3887        Self { inner: opts }
3888    }
3889}
3890
3891impl Drop for CompactOptions {
3892    fn drop(&mut self) {
3893        unsafe {
3894            ffi::rocksdb_compactoptions_destroy(self.inner);
3895        }
3896    }
3897}
3898
3899impl CompactOptions {
3900    /// If more than one thread calls manual compaction,
3901    /// only one will actually schedule it while the other threads will simply wait
3902    /// for the scheduled manual compaction to complete. If exclusive_manual_compaction
3903    /// is set to true, the call will disable scheduling of automatic compaction jobs
3904    /// and wait for existing automatic compaction jobs to finish.
3905    pub fn set_exclusive_manual_compaction(&mut self, v: bool) {
3906        unsafe {
3907            ffi::rocksdb_compactoptions_set_exclusive_manual_compaction(
3908                self.inner,
3909                c_uchar::from(v),
3910            );
3911        }
3912    }
3913
3914    /// Sets bottommost level compaction.
3915    pub fn set_bottommost_level_compaction(&mut self, lvl: BottommostLevelCompaction) {
3916        unsafe {
3917            ffi::rocksdb_compactoptions_set_bottommost_level_compaction(self.inner, lvl as c_uchar);
3918        }
3919    }
3920
3921    /// If true, compacted files will be moved to the minimum level capable
3922    /// of holding the data or given level (specified non-negative target_level).
3923    pub fn set_change_level(&mut self, v: bool) {
3924        unsafe {
3925            ffi::rocksdb_compactoptions_set_change_level(self.inner, c_uchar::from(v));
3926        }
3927    }
3928
3929    /// If change_level is true and target_level have non-negative value, compacted
3930    /// files will be moved to target_level.
3931    pub fn set_target_level(&mut self, lvl: c_int) {
3932        unsafe {
3933            ffi::rocksdb_compactoptions_set_target_level(self.inner, lvl);
3934        }
3935    }
3936}
3937
3938/// Represents a path where sst files can be put into
3939pub struct DBPath {
3940    pub(crate) inner: *mut ffi::rocksdb_dbpath_t,
3941}
3942
3943impl DBPath {
3944    /// Create a new path
3945    pub fn new<P: AsRef<Path>>(path: P, target_size: u64) -> Result<Self, Error> {
3946        let p = to_cpath(path.as_ref()).unwrap();
3947        let dbpath = unsafe { ffi::rocksdb_dbpath_create(p.as_ptr(), target_size) };
3948        if dbpath.is_null() {
3949            Err(Error::new(format!(
3950                "Could not create path for storing sst files at location: {}",
3951                path.as_ref().display()
3952            )))
3953        } else {
3954            Ok(DBPath { inner: dbpath })
3955        }
3956    }
3957}
3958
3959impl Drop for DBPath {
3960    fn drop(&mut self) {
3961        unsafe {
3962            ffi::rocksdb_dbpath_destroy(self.inner);
3963        }
3964    }
3965}
3966
3967#[cfg(test)]
3968mod tests {
3969    use crate::{MemtableFactory, Options};
3970
3971    #[test]
3972    fn test_enable_statistics() {
3973        let mut opts = Options::default();
3974        opts.enable_statistics();
3975        opts.set_stats_dump_period_sec(60);
3976        assert!(opts.get_statistics().is_some());
3977
3978        let opts = Options::default();
3979        assert!(opts.get_statistics().is_none());
3980    }
3981
3982    #[test]
3983    fn test_set_memtable_factory() {
3984        let mut opts = Options::default();
3985        opts.set_memtable_factory(MemtableFactory::Vector);
3986        opts.set_memtable_factory(MemtableFactory::HashLinkList { bucket_count: 100 });
3987        opts.set_memtable_factory(MemtableFactory::HashSkipList {
3988            bucket_count: 100,
3989            height: 4,
3990            branching_factor: 4,
3991        });
3992    }
3993
3994    #[test]
3995    fn test_set_stats_persist_period_sec() {
3996        let mut opts = Options::default();
3997        opts.enable_statistics();
3998        opts.set_stats_persist_period_sec(5);
3999        assert!(opts.get_statistics().is_some());
4000
4001        let opts = Options::default();
4002        assert!(opts.get_statistics().is_none());
4003    }
4004}