mappum_rocksdb/
db_options.rs

1// Copyright 2014 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, CString};
16use std::mem;
17use std::path::Path;
18
19use libc::{self, c_int, c_uchar, c_uint, c_void, size_t};
20
21use crate::{
22    compaction_filter::{self, filter_callback, CompactionFilterCallback, CompactionFilterFn},
23    comparator::{self, ComparatorCallback, CompareFn},
24    ffi,
25    merge_operator::{
26        self, full_merge_callback, partial_merge_callback, MergeFn, MergeOperatorCallback,
27    },
28    slice_transform::SliceTransform,
29    BlockBasedIndexType, BlockBasedOptions, DBCompactionStyle, DBCompressionType, DBRecoveryMode,
30    FlushOptions, MemtableFactory, Options, PlainTableFactoryOptions, WriteOptions,
31};
32
33pub fn new_cache(capacity: size_t) -> *mut ffi::rocksdb_cache_t {
34    unsafe { ffi::rocksdb_cache_create_lru(capacity) }
35}
36
37// Safety note: auto-implementing Send on most db-related types is prevented by the inner FFI
38// pointer. In most cases, however, this pointer is Send-safe because it is never aliased and
39// rocksdb internally does not rely on thread-local information for its user-exposed types.
40unsafe impl Send for Options {}
41unsafe impl Send for WriteOptions {}
42unsafe impl Send for BlockBasedOptions {}
43// Sync is similarly safe for many types because they do not expose interior mutability, and their
44// use within the rocksdb library is generally behind a const reference
45unsafe impl Sync for Options {}
46unsafe impl Sync for WriteOptions {}
47unsafe impl Sync for BlockBasedOptions {}
48
49impl Drop for Options {
50    fn drop(&mut self) {
51        unsafe {
52            ffi::rocksdb_options_destroy(self.inner);
53        }
54    }
55}
56
57impl Drop for BlockBasedOptions {
58    fn drop(&mut self) {
59        unsafe {
60            ffi::rocksdb_block_based_options_destroy(self.inner);
61        }
62    }
63}
64
65impl Drop for FlushOptions {
66    fn drop(&mut self) {
67        unsafe {
68            ffi::rocksdb_flushoptions_destroy(self.inner);
69        }
70    }
71}
72
73impl Drop for WriteOptions {
74    fn drop(&mut self) {
75        unsafe {
76            ffi::rocksdb_writeoptions_destroy(self.inner);
77        }
78    }
79}
80
81impl BlockBasedOptions {
82    pub fn set_block_size(&mut self, size: usize) {
83        unsafe {
84            ffi::rocksdb_block_based_options_set_block_size(self.inner, size);
85        }
86    }
87
88    pub fn set_lru_cache(&mut self, size: size_t) {
89        let cache = new_cache(size);
90        unsafe {
91            // Since cache is wrapped in shared_ptr, we don't need to
92            // call rocksdb_cache_destroy explicitly.
93            ffi::rocksdb_block_based_options_set_block_cache(self.inner, cache);
94        }
95    }
96
97    pub fn disable_cache(&mut self) {
98        unsafe {
99            ffi::rocksdb_block_based_options_set_no_block_cache(self.inner, true as c_uchar);
100        }
101    }
102
103    pub fn set_bloom_filter(&mut self, bits_per_key: c_int, block_based: bool) {
104        unsafe {
105            let bloom = if block_based {
106                ffi::rocksdb_filterpolicy_create_bloom(bits_per_key)
107            } else {
108                ffi::rocksdb_filterpolicy_create_bloom_full(bits_per_key)
109            };
110
111            ffi::rocksdb_block_based_options_set_filter_policy(self.inner, bloom);
112        }
113    }
114
115    pub fn set_cache_index_and_filter_blocks(&mut self, v: bool) {
116        unsafe {
117            ffi::rocksdb_block_based_options_set_cache_index_and_filter_blocks(self.inner, v as u8);
118        }
119    }
120
121    /// Defines the index type to be used for SS-table lookups.
122    ///
123    /// # Example
124    ///
125    /// ```
126    /// use rocksdb::{BlockBasedOptions, BlockBasedIndexType, Options};
127    ///
128    /// let mut opts = Options::default();
129    /// let mut block_opts = BlockBasedOptions::default();
130    /// block_opts.set_index_type(BlockBasedIndexType::HashSearch);
131    /// ```
132    pub fn set_index_type(&mut self, index_type: BlockBasedIndexType) {
133        let index = index_type as i32;
134        unsafe {
135            ffi::rocksdb_block_based_options_set_index_type(self.inner, index);
136        }
137    }
138
139    /// If cache_index_and_filter_blocks is true and the below is true, then
140    /// filter and index blocks are stored in the cache, but a reference is
141    /// held in the "table reader" object so the blocks are pinned and only
142    /// evicted from cache when the table reader is freed.
143    ///
144    /// Default: false.
145    pub fn set_pin_l0_filter_and_index_blocks_in_cache(&mut self, v: bool) {
146        unsafe {
147            ffi::rocksdb_block_based_options_set_pin_l0_filter_and_index_blocks_in_cache(
148                self.inner,
149                v as c_uchar,
150            );
151        }
152    }
153
154    /// Format version, reserved for backward compatibility.
155    /// See https://github.com/facebook/rocksdb/blob/f059c7d9b96300091e07429a60f4ad55dac84859/include/rocksdb/table.h#L249-L274.
156    ///
157    /// Default: 2.
158    pub fn set_format_version(&mut self, version: i32) {
159        unsafe {
160            ffi::rocksdb_block_based_options_set_format_version(self.inner, version);
161        }
162    }
163
164    /// Number of keys between restart points for delta encoding of keys.
165    /// This parameter can be changed dynamically. Most clients should
166    /// leave this parameter alone. The minimum value allowed is 1. Any smaller
167    /// value will be silently overwritten with 1.
168    ///
169    /// Default: 16.
170    pub fn set_block_restart_interval(&mut self, interval: i32) {
171        unsafe {
172            ffi::rocksdb_block_based_options_set_block_restart_interval(self.inner, interval);
173        }
174    }
175
176    /// Same as block_restart_interval but used for the index block.
177    /// If you don't plan to run RocksDB before version 5.16 and you are
178    /// using `index_block_restart_interval` > 1, you should
179    /// probably set the `format_version` to >= 4 as it would reduce the index size.
180    ///
181    /// Default: 1.
182    pub fn set_index_block_restart_interval(&mut self, interval: i32) {
183        unsafe {
184            ffi::rocksdb_block_based_options_set_index_block_restart_interval(self.inner, interval);
185        }
186    }
187}
188
189impl Default for BlockBasedOptions {
190    fn default() -> BlockBasedOptions {
191        let block_opts = unsafe { ffi::rocksdb_block_based_options_create() };
192        if block_opts.is_null() {
193            panic!("Could not create RocksDB block based options");
194        }
195        BlockBasedOptions { inner: block_opts }
196    }
197}
198
199impl Options {
200    /// By default, RocksDB uses only one background thread for flush and
201    /// compaction. Calling this function will set it up such that total of
202    /// `total_threads` is used. Good value for `total_threads` is the number of
203    /// cores. You almost definitely want to call this function if your system is
204    /// bottlenecked by RocksDB.
205    ///
206    /// # Example
207    ///
208    /// ```
209    /// use rocksdb::Options;
210    ///
211    /// let mut opts = Options::default();
212    /// opts.increase_parallelism(3);
213    /// ```
214    pub fn increase_parallelism(&mut self, parallelism: i32) {
215        unsafe {
216            ffi::rocksdb_options_increase_parallelism(self.inner, parallelism);
217        }
218    }
219
220    pub fn optimize_level_style_compaction(&mut self, memtable_memory_budget: usize) {
221        unsafe {
222            ffi::rocksdb_options_optimize_level_style_compaction(
223                self.inner,
224                memtable_memory_budget as u64,
225            );
226        }
227    }
228
229    /// If true, the database will be created if it is missing.
230    ///
231    /// Default: `false`
232    ///
233    /// # Example
234    ///
235    /// ```
236    /// use rocksdb::Options;
237    ///
238    /// let mut opts = Options::default();
239    /// opts.create_if_missing(true);
240    /// ```
241    pub fn create_if_missing(&mut self, create_if_missing: bool) {
242        unsafe {
243            ffi::rocksdb_options_set_create_if_missing(self.inner, create_if_missing as c_uchar);
244        }
245    }
246
247    /// If true, any column families that didn't exist when opening the database
248    /// will be created.
249    ///
250    /// Default: `false`
251    ///
252    /// # Example
253    ///
254    /// ```
255    /// use rocksdb::Options;
256    ///
257    /// let mut opts = Options::default();
258    /// opts.create_missing_column_families(true);
259    /// ```
260    pub fn create_missing_column_families(&mut self, create_missing_cfs: bool) {
261        unsafe {
262            ffi::rocksdb_options_set_create_missing_column_families(
263                self.inner,
264                create_missing_cfs as c_uchar,
265            );
266        }
267    }
268
269    /// Sets the compression algorithm that will be used for the bottommost level that
270    /// contain files. If level-compaction is used, this option will only affect
271    /// levels after base level.
272    ///
273    /// Default: DBCompressionType::None
274    ///
275    /// # Example
276    ///
277    /// ```
278    /// use rocksdb::{Options, DBCompressionType};
279    ///
280    /// let mut opts = Options::default();
281    /// opts.set_compression_type(DBCompressionType::Snappy);
282    /// ```
283    pub fn set_compression_type(&mut self, t: DBCompressionType) {
284        unsafe {
285            ffi::rocksdb_options_set_compression(self.inner, t as c_int);
286        }
287    }
288
289    /// Different levels can have different compression policies. There
290    /// are cases where most lower levels would like to use quick compression
291    /// algorithms while the higher levels (which have more data) use
292    /// compression algorithms that have better compression but could
293    /// be slower. This array, if non-empty, should have an entry for
294    /// each level of the database; these override the value specified in
295    /// the previous field 'compression'.
296    ///
297    /// # Example
298    ///
299    /// ```
300    /// use rocksdb::{Options, DBCompressionType};
301    ///
302    /// let mut opts = Options::default();
303    /// opts.set_compression_per_level(&[
304    ///     DBCompressionType::None,
305    ///     DBCompressionType::None,
306    ///     DBCompressionType::Snappy,
307    ///     DBCompressionType::Snappy,
308    ///     DBCompressionType::Snappy
309    /// ]);
310    /// ```
311    pub fn set_compression_per_level(&mut self, level_types: &[DBCompressionType]) {
312        unsafe {
313            let mut level_types: Vec<_> = level_types.iter().map(|&t| t as c_int).collect();
314            ffi::rocksdb_options_set_compression_per_level(
315                self.inner,
316                level_types.as_mut_ptr(),
317                level_types.len() as size_t,
318            )
319        }
320    }
321
322    /// Maximum size of dictionaries used to prime the compression library.
323    /// Enabling dictionary can improve compression ratios when there are
324    /// repetitions across data blocks.
325    ///
326    /// The dictionary is created by sampling the SST file data. If
327    /// `zstd_max_train_bytes` is nonzero, the samples are passed through zstd's
328    /// dictionary generator. Otherwise, the random samples are used directly as
329    /// the dictionary.
330    ///
331    /// When compression dictionary is disabled, we compress and write each block
332    /// before buffering data for the next one. When compression dictionary is
333    /// enabled, we buffer all SST file data in-memory so we can sample it, as data
334    /// can only be compressed and written after the dictionary has been finalized.
335    /// So users of this feature may see increased memory usage.
336    ///
337    /// Default: `0`
338    ///
339    /// # Example
340    ///
341    /// ```
342    /// use rocksdb::Options;
343    ///
344    /// let mut opts = Options::default();
345    /// opts.set_compression_options(4, 5, 6, 7);
346    /// ```
347    pub fn set_compression_options(
348        &mut self,
349        w_bits: c_int,
350        level: c_int,
351        strategy: c_int,
352        max_dict_bytes: c_int,
353    ) {
354        unsafe {
355            ffi::rocksdb_options_set_compression_options(
356                self.inner,
357                w_bits,
358                level,
359                strategy,
360                max_dict_bytes,
361            );
362        }
363    }
364
365    /// If non-zero, we perform bigger reads when doing compaction. If you're
366    /// running RocksDB on spinning disks, you should set this to at least 2MB.
367    /// That way RocksDB's compaction is doing sequential instead of random reads.
368    ///
369    /// When non-zero, we also force new_table_reader_for_compaction_inputs to
370    /// true.
371    ///
372    /// Default: `0`
373    pub fn set_compaction_readahead_size(&mut self, compaction_readahead_size: usize) {
374        unsafe {
375            ffi::rocksdb_options_compaction_readahead_size(
376                self.inner,
377                compaction_readahead_size as usize,
378            );
379        }
380    }
381
382    /// Allow RocksDB to pick dynamic base of bytes for levels.
383    /// With this feature turned on, RocksDB will automatically adjust max bytes for each level.
384    /// The goal of this feature is to have lower bound on size amplification.
385    ///
386    /// Default: false.
387    pub fn set_level_compaction_dynamic_level_bytes(&mut self, v: bool) {
388        unsafe {
389            ffi::rocksdb_options_set_level_compaction_dynamic_level_bytes(self.inner, v as c_uchar);
390        }
391    }
392
393    pub fn set_merge_operator(
394        &mut self,
395        name: &str,
396        full_merge_fn: MergeFn,
397        partial_merge_fn: Option<MergeFn>,
398    ) {
399        let cb = Box::new(MergeOperatorCallback {
400            name: CString::new(name.as_bytes()).unwrap(),
401            full_merge_fn,
402            partial_merge_fn: partial_merge_fn.unwrap_or(full_merge_fn),
403        });
404
405        unsafe {
406            let mo = ffi::rocksdb_mergeoperator_create(
407                mem::transmute(cb),
408                Some(merge_operator::destructor_callback),
409                Some(full_merge_callback),
410                Some(partial_merge_callback),
411                None,
412                Some(merge_operator::name_callback),
413            );
414            ffi::rocksdb_options_set_merge_operator(self.inner, mo);
415        }
416    }
417
418    #[deprecated(
419        since = "0.5.0",
420        note = "add_merge_operator has been renamed to set_merge_operator"
421    )]
422    pub fn add_merge_operator(&mut self, name: &str, merge_fn: MergeFn) {
423        self.set_merge_operator(name, merge_fn, None);
424    }
425
426    /// Sets a compaction filter used to determine if entries should be kept, changed,
427    /// or removed during compaction.
428    ///
429    /// An example use case is to remove entries with an expired TTL.
430    ///
431    /// If you take a snapshot of the database, only values written since the last
432    /// snapshot will be passed through the compaction filter.
433    ///
434    /// If multi-threaded compaction is used, `filter_fn` may be called multiple times
435    /// simultaneously.
436    pub fn set_compaction_filter<F>(&mut self, name: &str, filter_fn: F)
437    where
438        F: CompactionFilterFn + Send + 'static,
439    {
440        let cb = Box::new(CompactionFilterCallback {
441            name: CString::new(name.as_bytes()).unwrap(),
442            filter_fn,
443        });
444
445        unsafe {
446            let cf = ffi::rocksdb_compactionfilter_create(
447                mem::transmute(cb),
448                Some(compaction_filter::destructor_callback::<F>),
449                Some(filter_callback::<F>),
450                Some(compaction_filter::name_callback::<F>),
451            );
452            ffi::rocksdb_options_set_compaction_filter(self.inner, cf);
453        }
454    }
455
456    /// Sets the comparator used to define the order of keys in the table.
457    /// Default: a comparator that uses lexicographic byte-wise ordering
458    ///
459    /// The client must ensure that the comparator supplied here has the same
460    /// name and orders keys *exactly* the same as the comparator provided to
461    /// previous open calls on the same DB.
462    pub fn set_comparator(&mut self, name: &str, compare_fn: CompareFn) {
463        let cb = Box::new(ComparatorCallback {
464            name: CString::new(name.as_bytes()).unwrap(),
465            f: compare_fn,
466        });
467
468        unsafe {
469            let cmp = ffi::rocksdb_comparator_create(
470                mem::transmute(cb),
471                Some(comparator::destructor_callback),
472                Some(comparator::compare_callback),
473                Some(comparator::name_callback),
474            );
475            ffi::rocksdb_options_set_comparator(self.inner, cmp);
476        }
477    }
478
479    pub fn set_prefix_extractor(&mut self, prefix_extractor: SliceTransform) {
480        unsafe { ffi::rocksdb_options_set_prefix_extractor(self.inner, prefix_extractor.inner) }
481    }
482
483    #[deprecated(
484        since = "0.5.0",
485        note = "add_comparator has been renamed to set_comparator"
486    )]
487    pub fn add_comparator(&mut self, name: &str, compare_fn: CompareFn) {
488        self.set_comparator(name, compare_fn);
489    }
490
491    pub fn optimize_for_point_lookup(&mut self, cache_size: u64) {
492        unsafe {
493            ffi::rocksdb_options_optimize_for_point_lookup(self.inner, cache_size);
494        }
495    }
496
497    /// Sets the optimize_filters_for_hits flag
498    ///
499    /// Default: `false`
500    ///
501    /// # Example
502    ///
503    /// ```
504    /// use rocksdb::Options;
505    ///
506    /// let mut opts = Options::default();
507    /// opts.set_optimize_filters_for_hits(true);
508    /// ```
509    pub fn set_optimize_filters_for_hits(&mut self, optimize_for_hits: bool) {
510        unsafe {
511            ffi::rocksdb_options_set_optimize_filters_for_hits(
512                self.inner,
513                optimize_for_hits as c_int,
514            );
515        }
516    }
517
518    /// Sets the number of open files that can be used by the DB. You may need to
519    /// increase this if your database has a large working set. Value `-1` means
520    /// files opened are always kept open. You can estimate number of files based
521    /// on target_file_size_base and target_file_size_multiplier for level-based
522    /// compaction. For universal-style compaction, you can usually set it to `-1`.
523    ///
524    /// Default: `-1`
525    ///
526    /// # Example
527    ///
528    /// ```
529    /// use rocksdb::Options;
530    ///
531    /// let mut opts = Options::default();
532    /// opts.set_max_open_files(10);
533    /// ```
534    pub fn set_max_open_files(&mut self, nfiles: c_int) {
535        unsafe {
536            ffi::rocksdb_options_set_max_open_files(self.inner, nfiles);
537        }
538    }
539
540    /// If true, then every store to stable storage will issue a fsync.
541    /// If false, then every store to stable storage will issue a fdatasync.
542    /// This parameter should be set to true while storing data to
543    /// filesystem like ext3 that can lose files after a reboot.
544    ///
545    /// Default: `false`
546    ///
547    /// # Example
548    ///
549    /// ```
550    /// use rocksdb::Options;
551    ///
552    /// let mut opts = Options::default();
553    /// opts.set_use_fsync(true);
554    /// ```
555    pub fn set_use_fsync(&mut self, useit: bool) {
556        unsafe { ffi::rocksdb_options_set_use_fsync(self.inner, useit as c_int) }
557    }
558
559    /// Allows OS to incrementally sync files to disk while they are being
560    /// written, asynchronously, in the background. This operation can be used
561    /// to smooth out write I/Os over time. Users shouldn't rely on it for
562    /// persistency guarantee.
563    /// Issue one request for every bytes_per_sync written. `0` turns it off.
564    ///
565    /// Default: `0`
566    ///
567    /// You may consider using rate_limiter to regulate write rate to device.
568    /// When rate limiter is enabled, it automatically enables bytes_per_sync
569    /// to 1MB.
570    ///
571    /// This option applies to table files
572    ///
573    /// # Example
574    ///
575    /// ```
576    /// use rocksdb::Options;
577    ///
578    /// let mut opts = Options::default();
579    /// opts.set_bytes_per_sync(1024 * 1024);
580    /// ```
581    pub fn set_bytes_per_sync(&mut self, nbytes: u64) {
582        unsafe {
583            ffi::rocksdb_options_set_bytes_per_sync(self.inner, nbytes);
584        }
585    }
586
587    /// If true, allow multi-writers to update mem tables in parallel.
588    /// Only some memtable_factory-s support concurrent writes; currently it
589    /// is implemented only for SkipListFactory.  Concurrent memtable writes
590    /// are not compatible with inplace_update_support or filter_deletes.
591    /// It is strongly recommended to set enable_write_thread_adaptive_yield
592    /// if you are going to use this feature.
593    ///
594    /// Default: true
595    ///
596    /// # Example
597    ///
598    /// ```
599    /// use rocksdb::Options;
600    ///
601    /// let mut opts = Options::default();
602    /// opts.set_allow_concurrent_memtable_write(false);
603    /// ```
604    pub fn set_allow_concurrent_memtable_write(&mut self, allow: bool) {
605        unsafe {
606            ffi::rocksdb_options_set_allow_concurrent_memtable_write(self.inner, allow as c_uchar)
607        }
608    }
609
610    /// Enable direct I/O mode for reading
611    /// they may or may not improve performance depending on the use case
612    ///
613    /// Files will be opened in "direct I/O" mode
614    /// which means that data read from the disk will not be cached or
615    /// buffered. The hardware buffer of the devices may however still
616    /// be used. Memory mapped files are not impacted by these parameters.
617    ///
618    /// Default: false
619    ///
620    /// # Example
621    ///
622    /// ```
623    /// use rocksdb::Options;
624    ///
625    /// let mut opts = Options::default();
626    /// opts.set_use_direct_reads(true);
627    /// ```
628    pub fn set_use_direct_reads(&mut self, enabled: bool) {
629        unsafe {
630            ffi::rocksdb_options_set_use_direct_reads(self.inner, enabled as c_uchar);
631        }
632    }
633
634    /// Enable direct I/O mode for flush and compaction
635    ///
636    /// Files will be opened in "direct I/O" mode
637    /// which means that data written to the disk will not be cached or
638    /// buffered. The hardware buffer of the devices may however still
639    /// be used. Memory mapped files are not impacted by these parameters.
640    /// they may or may not improve performance depending on the use case
641    ///
642    /// Default: false
643    ///
644    /// # Example
645    ///
646    /// ```
647    /// use rocksdb::Options;
648    ///
649    /// let mut opts = Options::default();
650    /// opts.set_use_direct_io_for_flush_and_compaction(true);
651    /// ```
652    pub fn set_use_direct_io_for_flush_and_compaction(&mut self, enabled: bool) {
653        unsafe {
654            ffi::rocksdb_options_set_use_direct_io_for_flush_and_compaction(
655                self.inner,
656                enabled as c_uchar,
657            );
658        }
659    }
660
661    /// Hints to the OS that it should not buffer disk I/O. Enabling this
662    /// parameter may improve performance but increases pressure on the
663    /// system cache.
664    ///
665    /// The exact behavior of this parameter is platform dependent.
666    ///
667    /// On POSIX systems, after RocksDB reads data from disk it will
668    /// mark the pages as "unneeded". The operating system may - or may not
669    /// - evict these pages from memory, reducing pressure on the system
670    /// cache. If the disk block is requested again this can result in
671    /// additional disk I/O.
672    ///
673    /// On WINDOWS systems, files will be opened in "unbuffered I/O" mode
674    /// which means that data read from the disk will not be cached or
675    /// bufferized. The hardware buffer of the devices may however still
676    /// be used. Memory mapped files are not impacted by this parameter.
677    ///
678    /// Default: true
679    ///
680    /// # Example
681    ///
682    /// ```
683    /// #[allow(deprecated)]
684    /// use rocksdb::Options;
685    ///
686    /// let mut opts = Options::default();
687    /// opts.set_allow_os_buffer(false);
688    /// ```
689    #[deprecated(
690        since = "0.7.0",
691        note = "replaced with set_use_direct_reads/set_use_direct_io_for_flush_and_compaction methods"
692    )]
693    pub fn set_allow_os_buffer(&mut self, is_allow: bool) {
694        self.set_use_direct_reads(!is_allow);
695        self.set_use_direct_io_for_flush_and_compaction(!is_allow);
696    }
697
698    /// Sets the number of shards used for table cache.
699    ///
700    /// Default: `6`
701    ///
702    /// # Example
703    ///
704    /// ```
705    /// use rocksdb::Options;
706    ///
707    /// let mut opts = Options::default();
708    /// opts.set_table_cache_num_shard_bits(4);
709    /// ```
710    pub fn set_table_cache_num_shard_bits(&mut self, nbits: c_int) {
711        unsafe {
712            ffi::rocksdb_options_set_table_cache_numshardbits(self.inner, nbits);
713        }
714    }
715
716    /// Sets the minimum number of write buffers that will be merged together
717    /// before writing to storage.  If set to `1`, then
718    /// all write buffers are flushed to L0 as individual files and this increases
719    /// read amplification because a get request has to check in all of these
720    /// files. Also, an in-memory merge may result in writing lesser
721    /// data to storage if there are duplicate records in each of these
722    /// individual write buffers.
723    ///
724    /// Default: `1`
725    ///
726    /// # Example
727    ///
728    /// ```
729    /// use rocksdb::Options;
730    ///
731    /// let mut opts = Options::default();
732    /// opts.set_min_write_buffer_number(2);
733    /// ```
734    pub fn set_min_write_buffer_number(&mut self, nbuf: c_int) {
735        unsafe {
736            ffi::rocksdb_options_set_min_write_buffer_number_to_merge(self.inner, nbuf);
737        }
738    }
739
740    /// Sets the maximum number of write buffers that are built up in memory.
741    /// The default and the minimum number is 2, so that when 1 write buffer
742    /// is being flushed to storage, new writes can continue to the other
743    /// write buffer.
744    /// If max_write_buffer_number > 3, writing will be slowed down to
745    /// options.delayed_write_rate if we are writing to the last write buffer
746    /// allowed.
747    ///
748    /// Default: `2`
749    ///
750    /// # Example
751    ///
752    /// ```
753    /// use rocksdb::Options;
754    ///
755    /// let mut opts = Options::default();
756    /// opts.set_max_write_buffer_number(4);
757    /// ```
758    pub fn set_max_write_buffer_number(&mut self, nbuf: c_int) {
759        unsafe {
760            ffi::rocksdb_options_set_max_write_buffer_number(self.inner, nbuf);
761        }
762    }
763
764    /// Sets the amount of data to build up in memory (backed by an unsorted log
765    /// on disk) before converting to a sorted on-disk file.
766    ///
767    /// Larger values increase performance, especially during bulk loads.
768    /// Up to max_write_buffer_number write buffers may be held in memory
769    /// at the same time,
770    /// so you may wish to adjust this parameter to control memory usage.
771    /// Also, a larger write buffer will result in a longer recovery time
772    /// the next time the database is opened.
773    ///
774    /// Note that write_buffer_size is enforced per column family.
775    /// See db_write_buffer_size for sharing memory across column families.
776    ///
777    /// Default: `0x4000000` (64MiB)
778    ///
779    /// Dynamically changeable through SetOptions() API
780    ///
781    /// # Example
782    ///
783    /// ```
784    /// use rocksdb::Options;
785    ///
786    /// let mut opts = Options::default();
787    /// opts.set_write_buffer_size(128 * 1024 * 1024);
788    /// ```
789    pub fn set_write_buffer_size(&mut self, size: usize) {
790        unsafe {
791            ffi::rocksdb_options_set_write_buffer_size(self.inner, size);
792        }
793    }
794
795    /// Amount of data to build up in memtables across all column
796    /// families before writing to disk.
797    ///
798    /// This is distinct from write_buffer_size, which enforces a limit
799    /// for a single memtable.
800    ///
801    /// This feature is disabled by default. Specify a non-zero value
802    /// to enable it.
803    ///
804    /// Default: 0 (disabled)
805    ///
806    /// # Example
807    ///
808    /// ```
809    /// use rocksdb::Options;
810    ///
811    /// let mut opts = Options::default();
812    /// opts.set_db_write_buffer_size(128 * 1024 * 1024);
813    /// ```
814    pub fn set_db_write_buffer_size(&mut self, size: usize) {
815        unsafe {
816            ffi::rocksdb_options_set_db_write_buffer_size(self.inner, size);
817        }
818    }
819
820    /// Control maximum total data size for a level.
821    /// max_bytes_for_level_base is the max total for level-1.
822    /// Maximum number of bytes for level L can be calculated as
823    /// (max_bytes_for_level_base) * (max_bytes_for_level_multiplier ^ (L-1))
824    /// For example, if max_bytes_for_level_base is 200MB, and if
825    /// max_bytes_for_level_multiplier is 10, total data size for level-1
826    /// will be 200MB, total file size for level-2 will be 2GB,
827    /// and total file size for level-3 will be 20GB.
828    ///
829    /// Default: `0x10000000` (256MiB).
830    ///
831    /// Dynamically changeable through SetOptions() API
832    ///
833    /// # Example
834    ///
835    /// ```
836    /// use rocksdb::Options;
837    ///
838    /// let mut opts = Options::default();
839    /// opts.set_max_bytes_for_level_base(512 * 1024 * 1024);
840    /// ```
841    pub fn set_max_bytes_for_level_base(&mut self, size: u64) {
842        unsafe {
843            ffi::rocksdb_options_set_max_bytes_for_level_base(self.inner, size);
844        }
845    }
846
847    /// Default: `10`
848    ///
849    /// # Example
850    ///
851    /// ```
852    /// use rocksdb::Options;
853    ///
854    /// let mut opts = Options::default();
855    /// opts.set_max_bytes_for_level_multiplier(4.0);
856    /// ```
857    pub fn set_max_bytes_for_level_multiplier(&mut self, mul: f64) {
858        unsafe {
859            ffi::rocksdb_options_set_max_bytes_for_level_multiplier(self.inner, mul);
860        }
861    }
862
863    /// The manifest file is rolled over on reaching this limit.
864    /// The older manifest file be deleted.
865    /// The default value is MAX_INT so that roll-over does not take place.
866    ///
867    /// # Example
868    ///
869    /// ```
870    /// use rocksdb::Options;
871    ///
872    /// let mut opts = Options::default();
873    /// opts.set_max_manifest_file_size(20 * 1024 * 1024);
874    /// ```
875    pub fn set_max_manifest_file_size(&mut self, size: usize) {
876        unsafe {
877            ffi::rocksdb_options_set_max_manifest_file_size(self.inner, size);
878        }
879    }
880
881    /// Sets the target file size for compaction.
882    /// target_file_size_base is per-file size for level-1.
883    /// Target file size for level L can be calculated by
884    /// target_file_size_base * (target_file_size_multiplier ^ (L-1))
885    /// For example, if target_file_size_base is 2MB and
886    /// target_file_size_multiplier is 10, then each file on level-1 will
887    /// be 2MB, and each file on level 2 will be 20MB,
888    /// and each file on level-3 will be 200MB.
889    ///
890    /// Default: `0x4000000` (64MiB)
891    ///
892    /// Dynamically changeable through SetOptions() API
893    ///
894    /// # Example
895    ///
896    /// ```
897    /// use rocksdb::Options;
898    ///
899    /// let mut opts = Options::default();
900    /// opts.set_target_file_size_base(128 * 1024 * 1024);
901    /// ```
902    pub fn set_target_file_size_base(&mut self, size: u64) {
903        unsafe {
904            ffi::rocksdb_options_set_target_file_size_base(self.inner, size);
905        }
906    }
907
908    /// Sets the minimum number of write buffers that will be merged together
909    /// before writing to storage.  If set to `1`, then
910    /// all write buffers are flushed to L0 as individual files and this increases
911    /// read amplification because a get request has to check in all of these
912    /// files. Also, an in-memory merge may result in writing lesser
913    /// data to storage if there are duplicate records in each of these
914    /// individual write buffers.
915    ///
916    /// Default: `1`
917    ///
918    /// # Example
919    ///
920    /// ```
921    /// use rocksdb::Options;
922    ///
923    /// let mut opts = Options::default();
924    /// opts.set_min_write_buffer_number_to_merge(2);
925    /// ```
926    pub fn set_min_write_buffer_number_to_merge(&mut self, to_merge: c_int) {
927        unsafe {
928            ffi::rocksdb_options_set_min_write_buffer_number_to_merge(self.inner, to_merge);
929        }
930    }
931
932    /// Sets the number of files to trigger level-0 compaction. A value < `0` means that
933    /// level-0 compaction will not be triggered by number of files at all.
934    ///
935    /// Default: `4`
936    ///
937    /// Dynamically changeable through SetOptions() API
938    ///
939    /// # Example
940    ///
941    /// ```
942    /// use rocksdb::Options;
943    ///
944    /// let mut opts = Options::default();
945    /// opts.set_level_zero_file_num_compaction_trigger(8);
946    /// ```
947    pub fn set_level_zero_file_num_compaction_trigger(&mut self, n: c_int) {
948        unsafe {
949            ffi::rocksdb_options_set_level0_file_num_compaction_trigger(self.inner, n);
950        }
951    }
952
953    /// Sets the soft limit on number of level-0 files. We start slowing down writes at this
954    /// point. A value < `0` means that no writing slow down will be triggered by
955    /// number of files in level-0.
956    ///
957    /// Default: `20`
958    ///
959    /// Dynamically changeable through SetOptions() API
960    ///
961    /// # Example
962    ///
963    /// ```
964    /// use rocksdb::Options;
965    ///
966    /// let mut opts = Options::default();
967    /// opts.set_level_zero_slowdown_writes_trigger(10);
968    /// ```
969    pub fn set_level_zero_slowdown_writes_trigger(&mut self, n: c_int) {
970        unsafe {
971            ffi::rocksdb_options_set_level0_slowdown_writes_trigger(self.inner, n);
972        }
973    }
974
975    /// Sets the maximum number of level-0 files.  We stop writes at this point.
976    ///
977    /// Default: `24`
978    ///
979    /// Dynamically changeable through SetOptions() API
980    ///
981    /// # Example
982    ///
983    /// ```
984    /// use rocksdb::Options;
985    ///
986    /// let mut opts = Options::default();
987    /// opts.set_level_zero_stop_writes_trigger(48);
988    /// ```
989    pub fn set_level_zero_stop_writes_trigger(&mut self, n: c_int) {
990        unsafe {
991            ffi::rocksdb_options_set_level0_stop_writes_trigger(self.inner, n);
992        }
993    }
994
995    /// Sets the compaction style.
996    ///
997    /// Default: DBCompactionStyle::Level
998    ///
999    /// # Example
1000    ///
1001    /// ```
1002    /// use rocksdb::{Options, DBCompactionStyle};
1003    ///
1004    /// let mut opts = Options::default();
1005    /// opts.set_compaction_style(DBCompactionStyle::Universal);
1006    /// ```
1007    pub fn set_compaction_style(&mut self, style: DBCompactionStyle) {
1008        unsafe {
1009            ffi::rocksdb_options_set_compaction_style(self.inner, style as c_int);
1010        }
1011    }
1012
1013    /// Sets the maximum number of concurrent background compaction jobs, submitted to
1014    /// the default LOW priority thread pool.
1015    /// We first try to schedule compactions based on
1016    /// `base_background_compactions`. If the compaction cannot catch up , we
1017    /// will increase number of compaction threads up to
1018    /// `max_background_compactions`.
1019    ///
1020    /// If you're increasing this, also consider increasing number of threads in
1021    /// LOW priority thread pool. For more information, see
1022    /// Env::SetBackgroundThreads
1023    ///
1024    /// Default: `1`
1025    ///
1026    /// # Example
1027    ///
1028    /// ```
1029    /// use rocksdb::Options;
1030    ///
1031    /// let mut opts = Options::default();
1032    /// opts.set_max_background_compactions(2);
1033    /// ```
1034    pub fn set_max_background_compactions(&mut self, n: c_int) {
1035        unsafe {
1036            ffi::rocksdb_options_set_max_background_compactions(self.inner, n);
1037        }
1038    }
1039
1040    /// Sets the maximum number of concurrent background memtable flush jobs, submitted to
1041    /// the HIGH priority thread pool.
1042    ///
1043    /// By default, all background jobs (major compaction and memtable flush) go
1044    /// to the LOW priority pool. If this option is set to a positive number,
1045    /// memtable flush jobs will be submitted to the HIGH priority pool.
1046    /// It is important when the same Env is shared by multiple db instances.
1047    /// Without a separate pool, long running major compaction jobs could
1048    /// potentially block memtable flush jobs of other db instances, leading to
1049    /// unnecessary Put stalls.
1050    ///
1051    /// If you're increasing this, also consider increasing number of threads in
1052    /// HIGH priority thread pool. For more information, see
1053    /// Env::SetBackgroundThreads
1054    ///
1055    /// Default: `1`
1056    ///
1057    /// # Example
1058    ///
1059    /// ```
1060    /// use rocksdb::Options;
1061    ///
1062    /// let mut opts = Options::default();
1063    /// opts.set_max_background_flushes(2);
1064    /// ```
1065    pub fn set_max_background_flushes(&mut self, n: c_int) {
1066        unsafe {
1067            ffi::rocksdb_options_set_max_background_flushes(self.inner, n);
1068        }
1069    }
1070
1071    /// Disables automatic compactions. Manual compactions can still
1072    /// be issued on this column family
1073    ///
1074    /// Default: `false`
1075    ///
1076    /// Dynamically changeable through SetOptions() API
1077    ///
1078    /// # Example
1079    ///
1080    /// ```
1081    /// use rocksdb::Options;
1082    ///
1083    /// let mut opts = Options::default();
1084    /// opts.set_disable_auto_compactions(true);
1085    /// ```
1086    pub fn set_disable_auto_compactions(&mut self, disable: bool) {
1087        unsafe { ffi::rocksdb_options_set_disable_auto_compactions(self.inner, disable as c_int) }
1088    }
1089
1090    /// Defines the underlying memtable implementation.
1091    /// See https://github.com/facebook/rocksdb/wiki/MemTable for more information.
1092    /// Defaults to using a skiplist.
1093    ///
1094    /// # Example
1095    ///
1096    /// ```
1097    /// use rocksdb::{Options, MemtableFactory};
1098    /// let mut opts = Options::default();
1099    /// let factory = MemtableFactory::HashSkipList {
1100    ///     bucket_count: 1_000_000,
1101    ///     height: 4,
1102    ///     branching_factor: 4,
1103    /// };
1104    ///
1105    /// opts.set_allow_concurrent_memtable_write(false);
1106    /// opts.set_memtable_factory(factory);
1107    /// ```
1108    pub fn set_memtable_factory(&mut self, factory: MemtableFactory) {
1109        match factory {
1110            MemtableFactory::Vector => unsafe {
1111                ffi::rocksdb_options_set_memtable_vector_rep(self.inner);
1112            },
1113            MemtableFactory::HashSkipList {
1114                bucket_count,
1115                height,
1116                branching_factor,
1117            } => unsafe {
1118                ffi::rocksdb_options_set_hash_skip_list_rep(
1119                    self.inner,
1120                    bucket_count,
1121                    height,
1122                    branching_factor,
1123                );
1124            },
1125            MemtableFactory::HashLinkList { bucket_count } => unsafe {
1126                ffi::rocksdb_options_set_hash_link_list_rep(self.inner, bucket_count);
1127            },
1128        };
1129    }
1130
1131    pub fn set_block_based_table_factory(&mut self, factory: &BlockBasedOptions) {
1132        unsafe {
1133            ffi::rocksdb_options_set_block_based_table_factory(self.inner, factory.inner);
1134        }
1135    }
1136
1137    /// See https://github.com/facebook/rocksdb/wiki/PlainTable-Format.
1138    ///
1139    /// ```
1140    /// use rocksdb::{Options, PlainTableFactoryOptions};
1141    ///
1142    /// let mut opts = Options::default();
1143    /// let factory_opts = PlainTableFactoryOptions {
1144    ///   user_key_length: 0,
1145    ///   bloom_bits_per_key: 20,
1146    ///   hash_table_ratio: 0.75,
1147    ///   index_sparseness: 16,
1148    /// };
1149    ///
1150    /// opts.set_plain_table_factory(&factory_opts);
1151    /// ```
1152    pub fn set_plain_table_factory(&mut self, options: &PlainTableFactoryOptions) {
1153        unsafe {
1154            ffi::rocksdb_options_set_plain_table_factory(
1155                self.inner,
1156                options.user_key_length,
1157                options.bloom_bits_per_key,
1158                options.hash_table_ratio,
1159                options.index_sparseness,
1160            );
1161        }
1162    }
1163
1164    /// Measure IO stats in compactions and flushes, if `true`.
1165    ///
1166    /// Default: `false`
1167    ///
1168    /// # Example
1169    ///
1170    /// ```
1171    /// use rocksdb::Options;
1172    ///
1173    /// let mut opts = Options::default();
1174    /// opts.set_report_bg_io_stats(true);
1175    /// ```
1176    pub fn set_report_bg_io_stats(&mut self, enable: bool) {
1177        unsafe {
1178            ffi::rocksdb_options_set_report_bg_io_stats(self.inner, enable as c_int);
1179        }
1180    }
1181
1182    /// Once write-ahead logs exceed this size, we will start forcing the flush of
1183    /// column families whose memtables are backed by the oldest live WAL file
1184    /// (i.e. the ones that are causing all the space amplification).
1185    ///
1186    /// Default: `0`
1187    ///
1188    /// # Example
1189    ///
1190    /// ```
1191    /// use rocksdb::Options;
1192    ///
1193    /// let mut opts = Options::default();
1194    /// // Set max total wal size to 1G.
1195    /// opts.set_max_total_wal_size(1 << 30);
1196    /// ```
1197    pub fn set_max_total_wal_size(&mut self, size: u64) {
1198        unsafe {
1199            ffi::rocksdb_options_set_max_total_wal_size(self.inner, size);
1200        }
1201    }
1202
1203    /// Recovery mode to control the consistency while replaying WAL.
1204    ///
1205    /// Default: DBRecoveryMode::PointInTime
1206    ///
1207    /// # Example
1208    ///
1209    /// ```
1210    /// use rocksdb::{Options, DBRecoveryMode};
1211    ///
1212    /// let mut opts = Options::default();
1213    /// opts.set_wal_recovery_mode(DBRecoveryMode::AbsoluteConsistency);
1214    /// ```
1215    pub fn set_wal_recovery_mode(&mut self, mode: DBRecoveryMode) {
1216        unsafe {
1217            ffi::rocksdb_options_set_wal_recovery_mode(self.inner, mode as c_int);
1218        }
1219    }
1220
1221    pub fn enable_statistics(&mut self) {
1222        unsafe {
1223            ffi::rocksdb_options_enable_statistics(self.inner);
1224        }
1225    }
1226
1227    pub fn get_statistics(&self) -> Option<String> {
1228        unsafe {
1229            let value = ffi::rocksdb_options_statistics_get_string(self.inner);
1230            if value.is_null() {
1231                return None;
1232            }
1233
1234            // Must have valid UTF-8 format.
1235            let s = CStr::from_ptr(value).to_str().unwrap().to_owned();
1236            libc::free(value as *mut c_void);
1237            Some(s)
1238        }
1239    }
1240
1241    /// If not zero, dump `rocksdb.stats` to LOG every `stats_dump_period_sec`.
1242    ///
1243    /// Default: `600` (10 mins)
1244    ///
1245    /// # Example
1246    ///
1247    /// ```
1248    /// use rocksdb::Options;
1249    ///
1250    /// let mut opts = Options::default();
1251    /// opts.set_stats_dump_period_sec(300);
1252    /// ```
1253    pub fn set_stats_dump_period_sec(&mut self, period: c_uint) {
1254        unsafe {
1255            ffi::rocksdb_options_set_stats_dump_period_sec(self.inner, period);
1256        }
1257    }
1258
1259    /// When set to true, reading SST files will opt out of the filesystem's
1260    /// readahead. Setting this to false may improve sequential iteration
1261    /// performance.
1262    ///
1263    /// Default: `true`
1264    pub fn set_advise_random_on_open(&mut self, advise: bool) {
1265        unsafe { ffi::rocksdb_options_set_advise_random_on_open(self.inner, advise as c_uchar) }
1266    }
1267
1268    /// Sets the number of levels for this database.
1269    pub fn set_num_levels(&mut self, n: c_int) {
1270        unsafe {
1271            ffi::rocksdb_options_set_num_levels(self.inner, n);
1272        }
1273    }
1274
1275    /// When a `prefix_extractor` is defined through `opts.set_prefix_extractor` this
1276    /// creates a prefix bloom filter for each memtable with the size of
1277    /// `write_buffer_size * memtable_prefix_bloom_ratio` (capped at 0.25).
1278    ///
1279    /// Default: `0`
1280    ///
1281    /// # Example
1282    ///
1283    /// ```
1284    /// use rocksdb::{Options, SliceTransform};
1285    ///
1286    /// let mut opts = Options::default();
1287    /// let transform = SliceTransform::create_fixed_prefix(10);
1288    /// opts.set_prefix_extractor(transform);
1289    /// opts.set_memtable_prefix_bloom_ratio(0.2);
1290    /// ```
1291    pub fn set_memtable_prefix_bloom_ratio(&mut self, ratio: f64) {
1292        unsafe {
1293            ffi::rocksdb_options_set_memtable_prefix_bloom_size_ratio(self.inner, ratio);
1294        }
1295    }
1296
1297    /// Specifies the absolute path of the directory the
1298    /// write-ahead log (WAL) should be written to.
1299    ///
1300    /// Default: same directory as the database
1301    ///
1302    /// # Example
1303    ///
1304    /// ```
1305    /// use rocksdb::Options;
1306    ///
1307    /// let mut opts = Options::default();
1308    /// opts.set_wal_dir("/path/to/dir");
1309    /// ```
1310    pub fn set_wal_dir<P: AsRef<Path>>(&mut self, path: P) {
1311        let p = CString::new(path.as_ref().to_string_lossy().as_bytes()).unwrap();
1312        unsafe {
1313            ffi::rocksdb_options_set_wal_dir(self.inner, p.as_ptr());
1314        }
1315    }
1316
1317    /// If true, then DB::Open() will not update the statistics used to optimize
1318    /// compaction decision by loading table properties from many files.
1319    /// Turning off this feature will improve DBOpen time especially in disk environment.
1320    ///
1321    /// Default: false
1322    pub fn set_skip_stats_update_on_db_open(&mut self, skip: bool) {
1323        unsafe {
1324            ffi::rocksdb_options_set_skip_stats_update_on_db_open(self.inner, skip as c_uchar);
1325        }
1326    }
1327
1328    /// Specify the maximal number of info log files to be kept.
1329    pub fn set_keep_log_file_num(&mut self, nfiles: usize) {
1330        unsafe {
1331            ffi::rocksdb_options_set_keep_log_file_num(self.inner, nfiles);
1332        }
1333    }
1334
1335    /// Allow the OS to mmap file for writing.
1336    ///
1337    /// Default: false
1338    ///
1339    /// # Example
1340    ///
1341    /// ```
1342    /// use rocksdb::Options;
1343    ///
1344    /// let mut options = Options::default();
1345    /// options.set_allow_mmap_writes(true);
1346    /// ```
1347    pub fn set_allow_mmap_writes(&mut self, is_enabled: bool) {
1348        unsafe {
1349            ffi::rocksdb_options_set_allow_mmap_writes(self.inner, is_enabled as c_uchar);
1350        }
1351    }
1352
1353    /// Allow the OS to mmap file for reading sst tables.
1354    ///
1355    /// Default: false
1356    ///
1357    /// # Example
1358    ///
1359    /// ```
1360    /// use rocksdb::Options;
1361    ///
1362    /// let mut options = Options::default();
1363    /// options.set_allow_mmap_reads(true);
1364    /// ```
1365    pub fn set_allow_mmap_reads(&mut self, is_enabled: bool) {
1366        unsafe {
1367            ffi::rocksdb_options_set_allow_mmap_reads(self.inner, is_enabled as c_uchar);
1368        }
1369    }
1370
1371    /// Guarantee that all column families are flushed together atomically.
1372    /// This option applies to both manual flushes (`db.flush()`) and automatic
1373    /// background flushes caused when memtables are filled.
1374    ///
1375    /// Default: false
1376    ///
1377    /// # Example
1378    ///
1379    /// ```
1380    /// use rocksdb::Options;
1381    ///
1382    /// let mut options = Options::default();
1383    /// options.set_atomic_flush(true);
1384    /// ```
1385    pub fn set_atomic_flush(&mut self, atomic_flush: bool) {
1386        unsafe {
1387            ffi::rocksdb_options_set_atomic_flush(self.inner, atomic_flush as c_uchar);
1388        }
1389    }
1390
1391    /// Use to control write rate of flush and compaction. Flush has higher
1392    /// priority than compaction.
1393    /// If rate limiter is enabled, bytes_per_sync is set to 1MB by default.
1394    ///
1395    /// Default: disable
1396    ///
1397    /// # Example
1398    ///
1399    /// ```
1400    /// use rocksdb::Options;
1401    ///
1402    /// let mut options = Options::default();
1403    /// options.set_ratelimiter(1024 * 1024, 100 * 1000, 10);
1404    /// ```
1405    pub fn set_ratelimiter(
1406        &mut self,
1407        rate_bytes_per_sec: i64,
1408        refill_period_us: i64,
1409        fairness: i32,
1410    ) {
1411        unsafe {
1412            let ratelimiter =
1413                ffi::rocksdb_ratelimiter_create(rate_bytes_per_sec, refill_period_us, fairness);
1414            // Since limiter is wrapped in shared_ptr, we don't need to
1415            // call rocksdb_ratelimiter_destroy explicitly.
1416            ffi::rocksdb_options_set_ratelimiter(self.inner, ratelimiter);
1417        }
1418    }
1419}
1420
1421impl Default for Options {
1422    fn default() -> Options {
1423        unsafe {
1424            let opts = ffi::rocksdb_options_create();
1425            if opts.is_null() {
1426                panic!("Could not create RocksDB options");
1427            }
1428            Options { inner: opts }
1429        }
1430    }
1431}
1432
1433impl FlushOptions {
1434    pub fn new() -> FlushOptions {
1435        FlushOptions::default()
1436    }
1437
1438    /// Waits until the flush is done.
1439    ///
1440    /// Default: true
1441    ///
1442    /// # Example
1443    ///
1444    /// ```
1445    /// use rocksdb::FlushOptions;
1446    ///
1447    /// let mut options = FlushOptions::default();
1448    /// options.set_wait(false);
1449    /// ```
1450    pub fn set_wait(&mut self, wait: bool) {
1451        unsafe {
1452            ffi::rocksdb_flushoptions_set_wait(self.inner, wait as c_uchar);
1453        }
1454    }
1455}
1456
1457impl Default for FlushOptions {
1458    fn default() -> FlushOptions {
1459        let flush_opts = unsafe { ffi::rocksdb_flushoptions_create() };
1460        if flush_opts.is_null() {
1461            panic!("Could not create RocksDB flush options");
1462        }
1463        FlushOptions { inner: flush_opts }
1464    }
1465}
1466
1467impl WriteOptions {
1468    pub fn new() -> WriteOptions {
1469        WriteOptions::default()
1470    }
1471
1472    pub fn set_sync(&mut self, sync: bool) {
1473        unsafe {
1474            ffi::rocksdb_writeoptions_set_sync(self.inner, sync as c_uchar);
1475        }
1476    }
1477
1478    pub fn disable_wal(&mut self, disable: bool) {
1479        unsafe {
1480            ffi::rocksdb_writeoptions_disable_WAL(self.inner, disable as c_int);
1481        }
1482    }
1483}
1484
1485impl Default for WriteOptions {
1486    fn default() -> WriteOptions {
1487        let write_opts = unsafe { ffi::rocksdb_writeoptions_create() };
1488        if write_opts.is_null() {
1489            panic!("Could not create RocksDB write options");
1490        }
1491        WriteOptions { inner: write_opts }
1492    }
1493}
1494
1495#[cfg(test)]
1496mod tests {
1497    use crate::{MemtableFactory, Options};
1498
1499    #[test]
1500    fn test_enable_statistics() {
1501        let mut opts = Options::default();
1502        opts.enable_statistics();
1503        opts.set_stats_dump_period_sec(60);
1504        assert!(opts.get_statistics().is_some());
1505
1506        let opts = Options::default();
1507        assert!(opts.get_statistics().is_none());
1508    }
1509
1510    #[test]
1511    fn test_set_memtable_factory() {
1512        let mut opts = Options::default();
1513        opts.set_memtable_factory(MemtableFactory::Vector);
1514        opts.set_memtable_factory(MemtableFactory::HashLinkList { bucket_count: 100 });
1515        opts.set_memtable_factory(MemtableFactory::HashSkipList {
1516            bucket_count: 100,
1517            height: 4,
1518            branching_factor: 4,
1519        });
1520    }
1521}