rust_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::panic::{catch_unwind, AssertUnwindSafe};
17use std::path::Path;
18use std::ptr::null_mut;
19use std::slice;
20use std::sync::Arc;
21
22use libc::{self, c_char, c_double, c_int, c_uchar, c_uint, c_void, size_t};
23
24use crate::cache::Cache;
25use crate::column_family::ColumnFamilyTtl;
26use crate::event_listener::{new_event_listener, EventListener};
27use crate::sst_file_manager::SstFileManager;
28use crate::statistics::{Histogram, HistogramData, StatsLevel};
29use crate::write_buffer_manager::WriteBufferManager;
30use crate::{
31    compaction_filter::{self, CompactionFilterCallback, CompactionFilterFn},
32    compaction_filter_factory::{self, CompactionFilterFactory},
33    comparator::{
34        ComparatorCallback, ComparatorWithTsCallback, CompareFn, CompareTsFn, CompareWithoutTsFn,
35    },
36    db::DBAccess,
37    env::Env,
38    ffi,
39    ffi_util::{from_cstr, to_cpath, CStrLike},
40    merge_operator::{
41        self, full_merge_callback, partial_merge_callback, MergeFn, MergeOperatorCallback,
42    },
43    slice_transform::SliceTransform,
44    statistics::Ticker,
45    ColumnFamilyDescriptor, Error, SnapshotWithThreadMode,
46};
47
48// must be Send and Sync because it will be called by RocksDB from different threads
49type LogCallbackFn = dyn Fn(LogLevel, &str) + 'static + Send + Sync;
50
51// Holds a log callback to ensure it outlives any Options and DBs that use it.
52struct LogCallback {
53    callback: Box<LogCallbackFn>,
54}
55
56#[derive(Default)]
57pub(crate) struct OptionsMustOutliveDB {
58    env: Option<Env>,
59    row_cache: Option<Cache>,
60    blob_cache: Option<Cache>,
61    block_based: Option<BlockBasedOptionsMustOutliveDB>,
62    write_buffer_manager: Option<WriteBufferManager>,
63    sst_file_manager: Option<SstFileManager>,
64    log_callback: Option<Arc<LogCallback>>,
65}
66
67impl OptionsMustOutliveDB {
68    pub(crate) fn clone(&self) -> Self {
69        Self {
70            env: self.env.clone(),
71            row_cache: self.row_cache.clone(),
72            blob_cache: self.blob_cache.clone(),
73            block_based: self
74                .block_based
75                .as_ref()
76                .map(BlockBasedOptionsMustOutliveDB::clone),
77            write_buffer_manager: self.write_buffer_manager.clone(),
78            sst_file_manager: self.sst_file_manager.clone(),
79            log_callback: self.log_callback.clone(),
80        }
81    }
82}
83
84#[derive(Default)]
85struct BlockBasedOptionsMustOutliveDB {
86    block_cache: Option<Cache>,
87}
88
89impl BlockBasedOptionsMustOutliveDB {
90    fn clone(&self) -> Self {
91        Self {
92            block_cache: self.block_cache.clone(),
93        }
94    }
95}
96
97/// Database-wide options around performance and behavior.
98///
99/// Please read the official tuning [guide](https://github.com/facebook/rocksdb/wiki/RocksDB-Tuning-Guide)
100/// and most importantly, measure performance under realistic workloads with realistic hardware.
101///
102/// # Examples
103///
104/// ```
105/// use rust_rocksdb::{Options, DB};
106/// use rust_rocksdb::DBCompactionStyle;
107///
108/// fn badly_tuned_for_somebody_elses_disk() -> DB {
109///    let path = "path/for/rocksdb/storageX";
110///    let mut opts = Options::default();
111///    opts.create_if_missing(true);
112///    opts.set_max_open_files(10000);
113///    opts.set_use_fsync(false);
114///    opts.set_bytes_per_sync(8388608);
115///    opts.optimize_for_point_lookup(1024);
116///    opts.set_table_cache_num_shard_bits(6);
117///    opts.set_max_write_buffer_number(32);
118///    opts.set_write_buffer_size(536870912);
119///    opts.set_target_file_size_base(1073741824);
120///    opts.set_min_write_buffer_number_to_merge(4);
121///    opts.set_level_zero_stop_writes_trigger(2000);
122///    opts.set_level_zero_slowdown_writes_trigger(0);
123///    opts.set_compaction_style(DBCompactionStyle::Universal);
124///    opts.set_disable_auto_compactions(true);
125///
126///    DB::open(&opts, path).unwrap()
127/// }
128/// ```
129pub struct Options {
130    pub(crate) inner: *mut ffi::rocksdb_options_t,
131    pub(crate) outlive: OptionsMustOutliveDB,
132}
133
134/// Optionally disable WAL or sync for this write.
135///
136/// # Examples
137///
138/// Making an unsafe write of a batch:
139///
140/// ```
141/// use rust_rocksdb::{DB, Options, WriteBatch, WriteOptions};
142///
143/// let tempdir = tempfile::Builder::new()
144///     .prefix("_path_for_rocksdb_storageY1")
145///     .tempdir()
146///     .expect("Failed to create temporary path for the _path_for_rocksdb_storageY1");
147/// let path = tempdir.path();
148/// {
149///     let db = DB::open_default(path).unwrap();
150///     let mut batch = WriteBatch::default();
151///     batch.put(b"my key", b"my value");
152///     batch.put(b"key2", b"value2");
153///     batch.put(b"key3", b"value3");
154///
155///     let mut write_options = WriteOptions::default();
156///     write_options.set_sync(false);
157///     write_options.disable_wal(true);
158///
159///     db.write_opt(&batch, &write_options);
160/// }
161/// let _ = DB::destroy(&Options::default(), path);
162/// ```
163pub struct WriteOptions {
164    pub(crate) inner: *mut ffi::rocksdb_writeoptions_t,
165}
166
167pub struct LruCacheOptions {
168    pub(crate) inner: *mut ffi::rocksdb_lru_cache_options_t,
169}
170
171/// Optionally wait for the memtable flush to be performed.
172///
173/// # Examples
174///
175/// Manually flushing the memtable:
176///
177/// ```
178/// use rust_rocksdb::{DB, Options, FlushOptions};
179///
180/// let tempdir = tempfile::Builder::new()
181///     .prefix("_path_for_rocksdb_storageY2")
182///     .tempdir()
183///     .expect("Failed to create temporary path for the _path_for_rocksdb_storageY2");
184/// let path = tempdir.path();
185/// {
186///     let db = DB::open_default(path).unwrap();
187///
188///     let mut flush_options = FlushOptions::default();
189///     flush_options.set_wait(true);
190///
191///     db.flush_opt(&flush_options);
192/// }
193/// let _ = DB::destroy(&Options::default(), path);
194/// ```
195pub struct FlushOptions {
196    pub(crate) inner: *mut ffi::rocksdb_flushoptions_t,
197}
198
199/// For configuring block-based file storage.
200pub struct BlockBasedOptions {
201    pub(crate) inner: *mut ffi::rocksdb_block_based_table_options_t,
202    outlive: BlockBasedOptionsMustOutliveDB,
203}
204
205pub struct ReadOptions {
206    pub(crate) inner: *mut ffi::rocksdb_readoptions_t,
207    // The `ReadOptions` owns a copy of the timestamp and iteration bounds.
208    // This is necessary to ensure the pointers we pass over the FFI live as
209    // long as the `ReadOptions`. This way, when performing the read operation,
210    // the pointers are guaranteed to be valid.
211    timestamp: Option<Vec<u8>>,
212    iter_start_ts: Option<Vec<u8>>,
213    iterate_upper_bound: Option<Vec<u8>>,
214    iterate_lower_bound: Option<Vec<u8>>,
215}
216
217/// Configuration of cuckoo-based storage.
218pub struct CuckooTableOptions {
219    pub(crate) inner: *mut ffi::rocksdb_cuckoo_table_options_t,
220}
221
222/// For configuring external files ingestion.
223///
224/// # Examples
225///
226/// Move files instead of copying them:
227///
228/// ```
229/// use rust_rocksdb::{DB, IngestExternalFileOptions, SstFileWriter, Options};
230///
231/// let writer_opts = Options::default();
232/// let mut writer = SstFileWriter::create(&writer_opts);
233/// let tempdir = tempfile::Builder::new()
234///     .tempdir()
235///     .expect("Failed to create temporary folder for the _path_for_sst_file");
236/// let path1 = tempdir.path().join("_path_for_sst_file");
237/// writer.open(path1.clone()).unwrap();
238/// writer.put(b"k1", b"v1").unwrap();
239/// writer.finish().unwrap();
240///
241/// let tempdir2 = tempfile::Builder::new()
242///     .prefix("_path_for_rocksdb_storageY3")
243///     .tempdir()
244///     .expect("Failed to create temporary path for the _path_for_rocksdb_storageY3");
245/// let path2 = tempdir2.path();
246/// {
247///   let db = DB::open_default(&path2).unwrap();
248///   let mut ingest_opts = IngestExternalFileOptions::default();
249///   ingest_opts.set_move_files(true);
250///   db.ingest_external_file_opts(&ingest_opts, vec![path1]).unwrap();
251/// }
252/// let _ = DB::destroy(&Options::default(), path2);
253/// ```
254pub struct IngestExternalFileOptions {
255    pub(crate) inner: *mut ffi::rocksdb_ingestexternalfileoptions_t,
256}
257
258// Safety note: auto-implementing Send on most db-related types is prevented by the inner FFI
259// pointer. In most cases, however, this pointer is Send-safe because it is never aliased and
260// rocksdb internally does not rely on thread-local information for its user-exposed types.
261unsafe impl Send for Options {}
262unsafe impl Send for WriteOptions {}
263unsafe impl Send for LruCacheOptions {}
264unsafe impl Send for FlushOptions {}
265unsafe impl Send for BlockBasedOptions {}
266unsafe impl Send for CuckooTableOptions {}
267unsafe impl Send for ReadOptions {}
268unsafe impl Send for IngestExternalFileOptions {}
269unsafe impl Send for CompactOptions {}
270unsafe impl Send for ImportColumnFamilyOptions {}
271
272// Sync is similarly safe for many types because they do not expose interior mutability, and their
273// use within the rocksdb library is generally behind a const reference
274unsafe impl Sync for Options {}
275unsafe impl Sync for WriteOptions {}
276unsafe impl Sync for LruCacheOptions {}
277unsafe impl Sync for FlushOptions {}
278unsafe impl Sync for BlockBasedOptions {}
279unsafe impl Sync for CuckooTableOptions {}
280unsafe impl Sync for ReadOptions {}
281unsafe impl Sync for IngestExternalFileOptions {}
282unsafe impl Sync for CompactOptions {}
283unsafe impl Sync for ImportColumnFamilyOptions {}
284
285impl Drop for Options {
286    fn drop(&mut self) {
287        unsafe {
288            ffi::rocksdb_options_destroy(self.inner);
289        }
290    }
291}
292
293impl Clone for Options {
294    fn clone(&self) -> Self {
295        let inner = unsafe { ffi::rocksdb_options_create_copy(self.inner) };
296        assert!(!inner.is_null(), "Could not copy RocksDB options");
297
298        Self {
299            inner,
300            outlive: self.outlive.clone(),
301        }
302    }
303}
304
305impl Drop for BlockBasedOptions {
306    fn drop(&mut self) {
307        unsafe {
308            ffi::rocksdb_block_based_options_destroy(self.inner);
309        }
310    }
311}
312
313impl Drop for CuckooTableOptions {
314    fn drop(&mut self) {
315        unsafe {
316            ffi::rocksdb_cuckoo_options_destroy(self.inner);
317        }
318    }
319}
320
321impl Drop for FlushOptions {
322    fn drop(&mut self) {
323        unsafe {
324            ffi::rocksdb_flushoptions_destroy(self.inner);
325        }
326    }
327}
328
329impl Drop for WriteOptions {
330    fn drop(&mut self) {
331        unsafe {
332            ffi::rocksdb_writeoptions_destroy(self.inner);
333        }
334    }
335}
336
337impl Drop for LruCacheOptions {
338    fn drop(&mut self) {
339        unsafe {
340            ffi::rocksdb_lru_cache_options_destroy(self.inner);
341        }
342    }
343}
344
345impl Drop for ReadOptions {
346    fn drop(&mut self) {
347        unsafe {
348            ffi::rocksdb_readoptions_destroy(self.inner);
349        }
350    }
351}
352
353impl Drop for IngestExternalFileOptions {
354    fn drop(&mut self) {
355        unsafe {
356            ffi::rocksdb_ingestexternalfileoptions_destroy(self.inner);
357        }
358    }
359}
360
361impl BlockBasedOptions {
362    /// Approximate size of user data packed per block. Note that the
363    /// block size specified here corresponds to uncompressed data. The
364    /// actual size of the unit read from disk may be smaller if
365    /// compression is enabled. This parameter can be changed dynamically.
366    pub fn set_block_size(&mut self, size: usize) {
367        unsafe {
368            ffi::rocksdb_block_based_options_set_block_size(self.inner, size);
369        }
370    }
371
372    /// Block size for partitioned metadata. Currently applied to indexes when
373    /// kTwoLevelIndexSearch is used and to filters when partition_filters is used.
374    /// Note: Since in the current implementation the filters and index partitions
375    /// are aligned, an index/filter block is created when either index or filter
376    /// block size reaches the specified limit.
377    ///
378    /// Note: this limit is currently applied to only index blocks; a filter
379    /// partition is cut right after an index block is cut.
380    pub fn set_metadata_block_size(&mut self, size: usize) {
381        unsafe {
382            ffi::rocksdb_block_based_options_set_metadata_block_size(self.inner, size as u64);
383        }
384    }
385
386    /// Note: currently this option requires kTwoLevelIndexSearch to be set as
387    /// well.
388    ///
389    /// Use partitioned full filters for each SST file. This option is
390    /// incompatible with block-based filters.
391    pub fn set_partition_filters(&mut self, size: bool) {
392        unsafe {
393            ffi::rocksdb_block_based_options_set_partition_filters(self.inner, c_uchar::from(size));
394        }
395    }
396
397    /// Sets global cache for blocks (user data is stored in a set of blocks, and
398    /// a block is the unit of reading from disk).
399    ///
400    /// If set, use the specified cache for blocks.
401    /// By default, rocksdb will automatically create and use an 8MB internal cache.
402    pub fn set_block_cache(&mut self, cache: &Cache) {
403        unsafe {
404            ffi::rocksdb_block_based_options_set_block_cache(self.inner, cache.0.inner.as_ptr());
405        }
406        self.outlive.block_cache = Some(cache.clone());
407    }
408
409    /// Disable block cache
410    pub fn disable_cache(&mut self) {
411        unsafe {
412            ffi::rocksdb_block_based_options_set_no_block_cache(self.inner, c_uchar::from(true));
413        }
414    }
415
416    /// Sets a [Bloom filter](https://github.com/facebook/rocksdb/wiki/RocksDB-Bloom-Filter)
417    /// policy to reduce disk reads.
418    ///
419    /// # Examples
420    ///
421    /// ```
422    /// use rust_rocksdb::BlockBasedOptions;
423    ///
424    /// let mut opts = BlockBasedOptions::default();
425    /// opts.set_bloom_filter(10.0, true);
426    /// ```
427    pub fn set_bloom_filter(&mut self, bits_per_key: c_double, block_based: bool) {
428        unsafe {
429            let bloom = if block_based {
430                ffi::rocksdb_filterpolicy_create_bloom(bits_per_key as _)
431            } else {
432                ffi::rocksdb_filterpolicy_create_bloom_full(bits_per_key as _)
433            };
434
435            ffi::rocksdb_block_based_options_set_filter_policy(self.inner, bloom);
436        }
437    }
438
439    /// Sets a [Ribbon filter](http://rocksdb.org/blog/2021/12/29/ribbon-filter.html)
440    /// policy to reduce disk reads.
441    ///
442    /// Ribbon filters use less memory in exchange for slightly more CPU usage
443    /// compared to an equivalent bloom filter.
444    ///
445    /// # Examples
446    ///
447    /// ```
448    /// use rust_rocksdb::BlockBasedOptions;
449    ///
450    /// let mut opts = BlockBasedOptions::default();
451    /// opts.set_ribbon_filter(10.0);
452    /// ```
453    pub fn set_ribbon_filter(&mut self, bloom_equivalent_bits_per_key: c_double) {
454        unsafe {
455            let ribbon = ffi::rocksdb_filterpolicy_create_ribbon(bloom_equivalent_bits_per_key);
456            ffi::rocksdb_block_based_options_set_filter_policy(self.inner, ribbon);
457        }
458    }
459
460    /// Sets a hybrid [Ribbon filter](http://rocksdb.org/blog/2021/12/29/ribbon-filter.html)
461    /// policy to reduce disk reads.
462    ///
463    /// Uses Bloom filters before the given level, and Ribbon filters for all
464    /// other levels. This combines the memory savings from Ribbon filters
465    /// with the lower CPU usage of Bloom filters.
466    ///
467    /// # Examples
468    ///
469    /// ```
470    /// use rust_rocksdb::BlockBasedOptions;
471    ///
472    /// let mut opts = BlockBasedOptions::default();
473    /// opts.set_hybrid_ribbon_filter(10.0, 2);
474    /// ```
475    pub fn set_hybrid_ribbon_filter(
476        &mut self,
477        bloom_equivalent_bits_per_key: c_double,
478        bloom_before_level: c_int,
479    ) {
480        unsafe {
481            let ribbon = ffi::rocksdb_filterpolicy_create_ribbon_hybrid(
482                bloom_equivalent_bits_per_key,
483                bloom_before_level,
484            );
485            ffi::rocksdb_block_based_options_set_filter_policy(self.inner, ribbon);
486        }
487    }
488
489    /// Whether to put index/filter blocks in the block cache. When false,
490    /// each "table reader" object will pre-load index/filter blocks during
491    /// table initialization. Index and filter partition blocks always use
492    /// block cache regardless of this option.
493    ///
494    /// Default: false
495    pub fn set_cache_index_and_filter_blocks(&mut self, v: bool) {
496        unsafe {
497            ffi::rocksdb_block_based_options_set_cache_index_and_filter_blocks(
498                self.inner,
499                c_uchar::from(v),
500            );
501        }
502    }
503
504    /// If `cache_index_and_filter_blocks` is enabled, cache index and filter
505    /// blocks with high priority. Depending on the block cache implementation,
506    /// index, filter, and other metadata blocks may be less likely to be
507    /// evicted than data blocks when this is set to true.
508    ///
509    /// Default: true.
510    pub fn set_cache_index_and_filter_blocks_with_high_priority(&mut self, v: bool) {
511        unsafe {
512            ffi::rocksdb_block_based_options_set_cache_index_and_filter_blocks_with_high_priority(
513                self.inner,
514                c_uchar::from(v),
515            );
516        }
517    }
518
519    /// Defines the index type to be used for SS-table lookups.
520    ///
521    /// # Examples
522    ///
523    /// ```
524    /// use rust_rocksdb::{BlockBasedOptions, BlockBasedIndexType, Options};
525    ///
526    /// let mut opts = Options::default();
527    /// let mut block_opts = BlockBasedOptions::default();
528    /// block_opts.set_index_type(BlockBasedIndexType::HashSearch);
529    /// ```
530    pub fn set_index_type(&mut self, index_type: BlockBasedIndexType) {
531        let index = index_type as i32;
532        unsafe {
533            ffi::rocksdb_block_based_options_set_index_type(self.inner, index);
534        }
535    }
536
537    /// If cache_index_and_filter_blocks is true and the below is true, then
538    /// filter and index blocks are stored in the cache, but a reference is
539    /// held in the "table reader" object so the blocks are pinned and only
540    /// evicted from cache when the table reader is freed.
541    ///
542    /// Default: false.
543    pub fn set_pin_l0_filter_and_index_blocks_in_cache(&mut self, v: bool) {
544        unsafe {
545            ffi::rocksdb_block_based_options_set_pin_l0_filter_and_index_blocks_in_cache(
546                self.inner,
547                c_uchar::from(v),
548            );
549        }
550    }
551
552    /// If cache_index_and_filter_blocks is true and the below is true, then
553    /// the top-level index of partitioned filter and index blocks are stored in
554    /// the cache, but a reference is held in the "table reader" object so the
555    /// blocks are pinned and only evicted from cache when the table reader is
556    /// freed. This is not limited to l0 in LSM tree.
557    ///
558    /// Default: true.
559    pub fn set_pin_top_level_index_and_filter(&mut self, v: bool) {
560        unsafe {
561            ffi::rocksdb_block_based_options_set_pin_top_level_index_and_filter(
562                self.inner,
563                c_uchar::from(v),
564            );
565        }
566    }
567
568    /// Format version, reserved for backward compatibility.
569    ///
570    /// See full [list](https://github.com/facebook/rocksdb/blob/v8.6.7/include/rocksdb/table.h#L493-L521)
571    /// of the supported versions.
572    ///
573    /// Default: 6.
574    pub fn set_format_version(&mut self, version: i32) {
575        unsafe {
576            ffi::rocksdb_block_based_options_set_format_version(self.inner, version);
577        }
578    }
579
580    /// Use delta encoding to compress keys in blocks.
581    /// ReadOptions::pin_data requires this option to be disabled.
582    ///
583    /// Default: true
584    pub fn set_use_delta_encoding(&mut self, enable: bool) {
585        unsafe {
586            ffi::rocksdb_block_based_options_set_use_delta_encoding(
587                self.inner,
588                c_uchar::from(enable),
589            );
590        }
591    }
592
593    /// Number of keys between restart points for delta encoding of keys.
594    /// This parameter can be changed dynamically. Most clients should
595    /// leave this parameter alone. The minimum value allowed is 1. Any smaller
596    /// value will be silently overwritten with 1.
597    ///
598    /// Default: 16.
599    pub fn set_block_restart_interval(&mut self, interval: i32) {
600        unsafe {
601            ffi::rocksdb_block_based_options_set_block_restart_interval(self.inner, interval);
602        }
603    }
604
605    /// Same as block_restart_interval but used for the index block.
606    /// If you don't plan to run RocksDB before version 5.16 and you are
607    /// using `index_block_restart_interval` > 1, you should
608    /// probably set the `format_version` to >= 4 as it would reduce the index size.
609    ///
610    /// Default: 1.
611    pub fn set_index_block_restart_interval(&mut self, interval: i32) {
612        unsafe {
613            ffi::rocksdb_block_based_options_set_index_block_restart_interval(self.inner, interval);
614        }
615    }
616
617    /// Set the data block index type for point lookups:
618    ///  `DataBlockIndexType::BinarySearch` to use binary search within the data block.
619    ///  `DataBlockIndexType::BinaryAndHash` to use the data block hash index in combination with
620    ///  the normal binary search.
621    ///
622    /// The hash table utilization ratio is adjustable using [`set_data_block_hash_ratio`](#method.set_data_block_hash_ratio), which is
623    /// valid only when using `DataBlockIndexType::BinaryAndHash`.
624    ///
625    /// Default: `BinarySearch`
626    /// # Examples
627    ///
628    /// ```
629    /// use rust_rocksdb::{BlockBasedOptions, DataBlockIndexType, Options};
630    ///
631    /// let mut opts = Options::default();
632    /// let mut block_opts = BlockBasedOptions::default();
633    /// block_opts.set_data_block_index_type(DataBlockIndexType::BinaryAndHash);
634    /// block_opts.set_data_block_hash_ratio(0.85);
635    /// ```
636    pub fn set_data_block_index_type(&mut self, index_type: DataBlockIndexType) {
637        let index_t = index_type as i32;
638        unsafe {
639            ffi::rocksdb_block_based_options_set_data_block_index_type(self.inner, index_t);
640        }
641    }
642
643    /// Set the data block hash index utilization ratio.
644    ///
645    /// The smaller the utilization ratio, the less hash collisions happen, and so reduce the risk for a
646    /// point lookup to fall back to binary search due to the collisions. A small ratio means faster
647    /// lookup at the price of more space overhead.
648    ///
649    /// Default: 0.75
650    pub fn set_data_block_hash_ratio(&mut self, ratio: f64) {
651        unsafe {
652            ffi::rocksdb_block_based_options_set_data_block_hash_ratio(self.inner, ratio);
653        }
654    }
655
656    /// If false, place only prefixes in the filter, not whole keys.
657    ///
658    /// Defaults to true.
659    pub fn set_whole_key_filtering(&mut self, v: bool) {
660        unsafe {
661            ffi::rocksdb_block_based_options_set_whole_key_filtering(self.inner, c_uchar::from(v));
662        }
663    }
664
665    /// Use the specified checksum type.
666    /// Newly created table files will be protected with this checksum type.
667    /// Old table files will still be readable, even though they have different checksum type.
668    pub fn set_checksum_type(&mut self, checksum_type: ChecksumType) {
669        unsafe {
670            ffi::rocksdb_block_based_options_set_checksum(self.inner, checksum_type as c_char);
671        }
672    }
673
674    /// If true, generate Bloom/Ribbon filters that minimize memory internal
675    /// fragmentation.
676    /// See official [wiki](
677    /// https://github.com/facebook/rocksdb/wiki/RocksDB-Bloom-Filter#reducing-internal-fragmentation)
678    /// for more information.
679    ///
680    /// Default: true.
681    /// # Examples
682    ///
683    /// ```
684    /// use rust_rocksdb::BlockBasedOptions;
685    ///
686    /// let mut opts = BlockBasedOptions::default();
687    /// opts.set_bloom_filter(10.0, true);
688    /// opts.set_optimize_filters_for_memory(true);
689    /// ```
690    pub fn set_optimize_filters_for_memory(&mut self, v: bool) {
691        unsafe {
692            ffi::rocksdb_block_based_options_set_optimize_filters_for_memory(
693                self.inner,
694                c_uchar::from(v),
695            );
696        }
697    }
698
699    /// The tier of block-based tables whose top-level index into metadata
700    /// partitions will be pinned. Currently indexes and filters may be
701    /// partitioned.
702    ///
703    /// Note `cache_index_and_filter_blocks` must be true for this option to have
704    /// any effect. Otherwise any top-level index into metadata partitions would be
705    /// held in table reader memory, outside the block cache.
706    ///
707    /// Default: `BlockBasedPinningTier:Fallback`
708    ///
709    /// # Example
710    ///
711    /// ```
712    /// use rust_rocksdb::{BlockBasedOptions, BlockBasedPinningTier, Options};
713    ///
714    /// let mut opts = Options::default();
715    /// let mut block_opts = BlockBasedOptions::default();
716    /// block_opts.set_top_level_index_pinning_tier(BlockBasedPinningTier::FlushAndSimilar);
717    /// ```
718    pub fn set_top_level_index_pinning_tier(&mut self, tier: BlockBasedPinningTier) {
719        unsafe {
720            ffi::rocksdb_block_based_options_set_top_level_index_pinning_tier(
721                self.inner,
722                tier as c_int,
723            );
724        }
725    }
726
727    /// The tier of block-based tables whose metadata partitions will be pinned.
728    /// Currently indexes and filters may be partitioned.
729    ///
730    /// Default: `BlockBasedPinningTier:Fallback`
731    ///
732    /// # Example
733    ///
734    /// ```
735    /// use rust_rocksdb::{BlockBasedOptions, BlockBasedPinningTier, Options};
736    ///
737    /// let mut opts = Options::default();
738    /// let mut block_opts = BlockBasedOptions::default();
739    /// block_opts.set_partition_pinning_tier(BlockBasedPinningTier::FlushAndSimilar);
740    /// ```
741    pub fn set_partition_pinning_tier(&mut self, tier: BlockBasedPinningTier) {
742        unsafe {
743            ffi::rocksdb_block_based_options_set_partition_pinning_tier(self.inner, tier as c_int);
744        }
745    }
746
747    /// The tier of block-based tables whose unpartitioned metadata blocks will be
748    /// pinned.
749    ///
750    /// Note `cache_index_and_filter_blocks` must be true for this option to have
751    /// any effect. Otherwise the unpartitioned meta-blocks would be held in table
752    /// reader memory, outside the block cache.
753    ///
754    /// Default: `BlockBasedPinningTier:Fallback`
755    ///
756    /// # Example
757    ///
758    /// ```
759    /// use rust_rocksdb::{BlockBasedOptions, BlockBasedPinningTier, Options};
760    ///
761    /// let mut opts = Options::default();
762    /// let mut block_opts = BlockBasedOptions::default();
763    /// block_opts.set_unpartitioned_pinning_tier(BlockBasedPinningTier::FlushAndSimilar);
764    /// ```
765    pub fn set_unpartitioned_pinning_tier(&mut self, tier: BlockBasedPinningTier) {
766        unsafe {
767            ffi::rocksdb_block_based_options_set_unpartitioned_pinning_tier(
768                self.inner,
769                tier as c_int,
770            );
771        }
772    }
773}
774
775impl Default for BlockBasedOptions {
776    fn default() -> Self {
777        let block_opts = unsafe { ffi::rocksdb_block_based_options_create() };
778        assert!(
779            !block_opts.is_null(),
780            "Could not create RocksDB block based options"
781        );
782
783        Self {
784            inner: block_opts,
785            outlive: BlockBasedOptionsMustOutliveDB::default(),
786        }
787    }
788}
789
790impl CuckooTableOptions {
791    /// Determines the utilization of hash tables. Smaller values
792    /// result in larger hash tables with fewer collisions.
793    /// Default: 0.9
794    pub fn set_hash_ratio(&mut self, ratio: f64) {
795        unsafe {
796            ffi::rocksdb_cuckoo_options_set_hash_ratio(self.inner, ratio);
797        }
798    }
799
800    /// A property used by builder to determine the depth to go to
801    /// to search for a path to displace elements in case of
802    /// collision. See Builder.MakeSpaceForKey method. Higher
803    /// values result in more efficient hash tables with fewer
804    /// lookups but take more time to build.
805    /// Default: 100
806    pub fn set_max_search_depth(&mut self, depth: u32) {
807        unsafe {
808            ffi::rocksdb_cuckoo_options_set_max_search_depth(self.inner, depth);
809        }
810    }
811
812    /// In case of collision while inserting, the builder
813    /// attempts to insert in the next cuckoo_block_size
814    /// locations before skipping over to the next Cuckoo hash
815    /// function. This makes lookups more cache friendly in case
816    /// of collisions.
817    /// Default: 5
818    pub fn set_cuckoo_block_size(&mut self, size: u32) {
819        unsafe {
820            ffi::rocksdb_cuckoo_options_set_cuckoo_block_size(self.inner, size);
821        }
822    }
823
824    /// If this option is enabled, user key is treated as uint64_t and its value
825    /// is used as hash value directly. This option changes builder's behavior.
826    /// Reader ignore this option and behave according to what specified in
827    /// table property.
828    /// Default: false
829    pub fn set_identity_as_first_hash(&mut self, flag: bool) {
830        unsafe {
831            ffi::rocksdb_cuckoo_options_set_identity_as_first_hash(self.inner, c_uchar::from(flag));
832        }
833    }
834
835    /// If this option is set to true, module is used during hash calculation.
836    /// This often yields better space efficiency at the cost of performance.
837    /// If this option is set to false, # of entries in table is constrained to
838    /// be power of two, and bit and is used to calculate hash, which is faster in general.
839    /// Default: true
840    pub fn set_use_module_hash(&mut self, flag: bool) {
841        unsafe {
842            ffi::rocksdb_cuckoo_options_set_use_module_hash(self.inner, c_uchar::from(flag));
843        }
844    }
845}
846
847impl Default for CuckooTableOptions {
848    fn default() -> Self {
849        let opts = unsafe { ffi::rocksdb_cuckoo_options_create() };
850        assert!(!opts.is_null(), "Could not create RocksDB cuckoo options");
851
852        Self { inner: opts }
853    }
854}
855
856// Verbosity of the LOG.
857#[derive(Debug, Copy, Clone, PartialEq, Eq)]
858#[repr(i32)]
859pub enum LogLevel {
860    Debug = 0,
861    Info,
862    Warn,
863    Error,
864    Fatal,
865    Header,
866}
867
868impl Options {
869    /// Constructs the DBOptions and ColumnFamilyDescriptors by loading the
870    /// latest RocksDB options file stored in the specified rocksdb database.
871    ///
872    /// *IMPORTANT*:
873    /// ROCKSDB DOES NOT STORE cf ttl in the options file. If you have set it via
874    /// [`ColumnFamilyDescriptor::new_with_ttl`] then you need to set it again after loading the options file.
875    /// Tll will be set to [`ColumnFamilyTtl::Disabled`] for all column families for your safety.
876    pub fn load_latest<P: AsRef<Path>>(
877        path: P,
878        env: Env,
879        ignore_unknown_options: bool,
880        cache: Cache,
881    ) -> Result<(Options, Vec<ColumnFamilyDescriptor>), Error> {
882        let path = to_cpath(path)?;
883        let mut db_options: *mut ffi::rocksdb_options_t = null_mut();
884        let mut num_column_families: usize = 0;
885        let mut column_family_names: *mut *mut c_char = null_mut();
886        let mut column_family_options: *mut *mut ffi::rocksdb_options_t = null_mut();
887        unsafe {
888            ffi_try!(ffi::rocksdb_load_latest_options(
889                path.as_ptr(),
890                env.0.inner,
891                ignore_unknown_options,
892                cache.0.inner.as_ptr(),
893                &mut db_options,
894                &mut num_column_families,
895                &mut column_family_names,
896                &mut column_family_options,
897            ));
898        }
899        let options = Options {
900            inner: db_options,
901            outlive: OptionsMustOutliveDB::default(),
902        };
903        let column_families = unsafe {
904            Options::read_column_descriptors(
905                num_column_families,
906                column_family_names,
907                column_family_options,
908            )
909        };
910        Ok((options, column_families))
911    }
912
913    /// read column descriptors from c pointers
914    #[inline]
915    unsafe fn read_column_descriptors(
916        num_column_families: usize,
917        column_family_names: *mut *mut c_char,
918        column_family_options: *mut *mut ffi::rocksdb_options_t,
919    ) -> Vec<ColumnFamilyDescriptor> {
920        unsafe {
921            let column_family_names_iter =
922                slice::from_raw_parts(column_family_names, num_column_families)
923                    .iter()
924                    .map(|ptr| from_cstr(*ptr));
925            let column_family_options_iter =
926                slice::from_raw_parts(column_family_options, num_column_families)
927                    .iter()
928                    .map(|ptr| Options {
929                        inner: *ptr,
930                        outlive: OptionsMustOutliveDB::default(),
931                    });
932            let column_descriptors = column_family_names_iter
933                .zip(column_family_options_iter)
934                .map(|(name, options)| ColumnFamilyDescriptor {
935                    name,
936                    options,
937                    ttl: ColumnFamilyTtl::Disabled,
938                })
939                .collect::<Vec<_>>();
940            // free pointers
941            for ptr in slice::from_raw_parts(column_family_names, num_column_families) {
942                ffi::rocksdb_free(*ptr as *mut c_void);
943            }
944            ffi::rocksdb_free(column_family_names as *mut c_void);
945            ffi::rocksdb_free(column_family_options as *mut c_void);
946            column_descriptors
947        }
948    }
949
950    /// Updates DBOptions with values parsed from a string.
951    ///
952    /// See official [wiki](
953    /// https://github.com/facebook/rocksdb/wiki/Option-String-and-Option-Map#option-string)
954    /// for more information.
955    pub fn set_options_from_string(&mut self, string: impl CStrLike) -> Result<&mut Self, Error> {
956        let c_string = string.into_c_string().unwrap();
957        let mut err: *mut c_char = null_mut();
958        let err_ptr: *mut *mut c_char = &mut err;
959        unsafe {
960            ffi::rocksdb_get_options_from_string(
961                self.inner,
962                c_string.as_ptr(),
963                self.inner,
964                err_ptr,
965            );
966        }
967
968        if err.is_null() {
969            Ok(self)
970        } else {
971            Err(Error::new(format!(
972                "Could not set options from string: {}",
973                crate::ffi_util::error_message(err)
974            )))
975        }
976    }
977
978    /// By default, RocksDB uses only one background thread for flush and
979    /// compaction. Calling this function will set it up such that total of
980    /// `total_threads` is used. Good value for `total_threads` is the number of
981    /// cores. You almost definitely want to call this function if your system is
982    /// bottlenecked by RocksDB.
983    ///
984    /// # Examples
985    ///
986    /// ```
987    /// use rust_rocksdb::Options;
988    ///
989    /// let mut opts = Options::default();
990    /// opts.increase_parallelism(3);
991    /// ```
992    pub fn increase_parallelism(&mut self, parallelism: i32) {
993        unsafe {
994            ffi::rocksdb_options_increase_parallelism(self.inner, parallelism);
995        }
996    }
997
998    /// Optimize level style compaction.
999    ///
1000    /// Default values for some parameters in `Options` are not optimized for heavy
1001    /// workloads and big datasets, which means you might observe write stalls under
1002    /// some conditions.
1003    ///
1004    /// This can be used as one of the starting points for tuning RocksDB options in
1005    /// such cases.
1006    ///
1007    /// Internally, it sets `write_buffer_size`, `min_write_buffer_number_to_merge`,
1008    /// `max_write_buffer_number`, `level0_file_num_compaction_trigger`,
1009    /// `target_file_size_base`, `max_bytes_for_level_base`, so it can override if those
1010    /// parameters were set before.
1011    ///
1012    /// It sets buffer sizes so that memory consumption would be constrained by
1013    /// `memtable_memory_budget`.
1014    pub fn optimize_level_style_compaction(&mut self, memtable_memory_budget: usize) {
1015        unsafe {
1016            ffi::rocksdb_options_optimize_level_style_compaction(
1017                self.inner,
1018                memtable_memory_budget as u64,
1019            );
1020        }
1021    }
1022
1023    /// Optimize universal style compaction.
1024    ///
1025    /// Default values for some parameters in `Options` are not optimized for heavy
1026    /// workloads and big datasets, which means you might observe write stalls under
1027    /// some conditions.
1028    ///
1029    /// This can be used as one of the starting points for tuning RocksDB options in
1030    /// such cases.
1031    ///
1032    /// Internally, it sets `write_buffer_size`, `min_write_buffer_number_to_merge`,
1033    /// `max_write_buffer_number`, `level0_file_num_compaction_trigger`,
1034    /// `target_file_size_base`, `max_bytes_for_level_base`, so it can override if those
1035    /// parameters were set before.
1036    ///
1037    /// It sets buffer sizes so that memory consumption would be constrained by
1038    /// `memtable_memory_budget`.
1039    pub fn optimize_universal_style_compaction(&mut self, memtable_memory_budget: usize) {
1040        unsafe {
1041            ffi::rocksdb_options_optimize_universal_style_compaction(
1042                self.inner,
1043                memtable_memory_budget as u64,
1044            );
1045        }
1046    }
1047
1048    /// If true, the database will be created if it is missing.
1049    ///
1050    /// Default: `false`
1051    ///
1052    /// # Examples
1053    ///
1054    /// ```
1055    /// use rust_rocksdb::Options;
1056    ///
1057    /// let mut opts = Options::default();
1058    /// opts.create_if_missing(true);
1059    /// ```
1060    pub fn create_if_missing(&mut self, create_if_missing: bool) {
1061        unsafe {
1062            ffi::rocksdb_options_set_create_if_missing(
1063                self.inner,
1064                c_uchar::from(create_if_missing),
1065            );
1066        }
1067    }
1068
1069    /// If true, any column families that didn't exist when opening the database
1070    /// will be created.
1071    ///
1072    /// Default: `false`
1073    ///
1074    /// # Examples
1075    ///
1076    /// ```
1077    /// use rust_rocksdb::Options;
1078    ///
1079    /// let mut opts = Options::default();
1080    /// opts.create_missing_column_families(true);
1081    /// ```
1082    pub fn create_missing_column_families(&mut self, create_missing_cfs: bool) {
1083        unsafe {
1084            ffi::rocksdb_options_set_create_missing_column_families(
1085                self.inner,
1086                c_uchar::from(create_missing_cfs),
1087            );
1088        }
1089    }
1090
1091    /// Specifies whether an error should be raised if the database already exists.
1092    ///
1093    /// Default: false
1094    pub fn set_error_if_exists(&mut self, enabled: bool) {
1095        unsafe {
1096            ffi::rocksdb_options_set_error_if_exists(self.inner, c_uchar::from(enabled));
1097        }
1098    }
1099
1100    /// Enable/disable paranoid checks.
1101    ///
1102    /// If true, the implementation will do aggressive checking of the
1103    /// data it is processing and will stop early if it detects any
1104    /// errors. This may have unforeseen ramifications: for example, a
1105    /// corruption of one DB entry may cause a large number of entries to
1106    /// become unreadable or for the entire DB to become unopenable.
1107    /// If any of the  writes to the database fails (Put, Delete, Merge, Write),
1108    /// the database will switch to read-only mode and fail all other
1109    /// Write operations.
1110    ///
1111    /// Default: false
1112    pub fn set_paranoid_checks(&mut self, enabled: bool) {
1113        unsafe {
1114            ffi::rocksdb_options_set_paranoid_checks(self.inner, c_uchar::from(enabled));
1115        }
1116    }
1117
1118    /// A list of paths where SST files can be put into, with its target size.
1119    /// Newer data is placed into paths specified earlier in the vector while
1120    /// older data gradually moves to paths specified later in the vector.
1121    ///
1122    /// For example, you have a flash device with 10GB allocated for the DB,
1123    /// as well as a hard drive of 2TB, you should config it to be:
1124    ///   [{"/flash_path", 10GB}, {"/hard_drive", 2TB}]
1125    ///
1126    /// The system will try to guarantee data under each path is close to but
1127    /// not larger than the target size. But current and future file sizes used
1128    /// by determining where to place a file are based on best-effort estimation,
1129    /// which means there is a chance that the actual size under the directory
1130    /// is slightly more than target size under some workloads. User should give
1131    /// some buffer room for those cases.
1132    ///
1133    /// If none of the paths has sufficient room to place a file, the file will
1134    /// be placed to the last path anyway, despite to the target size.
1135    ///
1136    /// Placing newer data to earlier paths is also best-efforts. User should
1137    /// expect user files to be placed in higher levels in some extreme cases.
1138    ///
1139    /// If left empty, only one path will be used, which is `path` passed when
1140    /// opening the DB.
1141    ///
1142    /// Default: empty
1143    pub fn set_db_paths(&mut self, paths: &[DBPath]) {
1144        let mut paths: Vec<_> = paths.iter().map(|path| path.inner.cast_const()).collect();
1145        let num_paths = paths.len();
1146        unsafe {
1147            ffi::rocksdb_options_set_db_paths(self.inner, paths.as_mut_ptr(), num_paths);
1148        }
1149    }
1150
1151    /// Use the specified object to interact with the environment,
1152    /// e.g. to read/write files, schedule background work, etc. In the near
1153    /// future, support for doing storage operations such as read/write files
1154    /// through env will be deprecated in favor of file_system.
1155    ///
1156    /// Default: Env::default()
1157    pub fn set_env(&mut self, env: &Env) {
1158        unsafe {
1159            ffi::rocksdb_options_set_env(self.inner, env.0.inner);
1160        }
1161        self.outlive.env = Some(env.clone());
1162    }
1163
1164    /// Sets the compression algorithm that will be used for compressing blocks.
1165    ///
1166    /// Default: `DBCompressionType::Snappy` (`DBCompressionType::None` if
1167    /// snappy feature is not enabled).
1168    ///
1169    /// # Examples
1170    ///
1171    /// ```
1172    /// use rust_rocksdb::{Options, DBCompressionType};
1173    ///
1174    /// let mut opts = Options::default();
1175    /// opts.set_compression_type(DBCompressionType::Snappy);
1176    /// ```
1177    pub fn set_compression_type(&mut self, t: DBCompressionType) {
1178        unsafe {
1179            ffi::rocksdb_options_set_compression(self.inner, t as c_int);
1180        }
1181    }
1182
1183    /// Number of threads for parallel compression.
1184    /// Parallel compression is enabled only if threads > 1.
1185    /// THE FEATURE IS STILL EXPERIMENTAL
1186    ///
1187    /// See [code](https://github.com/facebook/rocksdb/blob/v8.6.7/include/rocksdb/advanced_options.h#L116-L127)
1188    /// for more information.
1189    ///
1190    /// Default: 1
1191    ///
1192    /// Examples
1193    ///
1194    /// ```
1195    /// use rust_rocksdb::{Options, DBCompressionType};
1196    ///
1197    /// let mut opts = Options::default();
1198    /// opts.set_compression_type(DBCompressionType::Zstd);
1199    /// opts.set_compression_options_parallel_threads(3);
1200    /// ```
1201    pub fn set_compression_options_parallel_threads(&mut self, num: i32) {
1202        unsafe {
1203            ffi::rocksdb_options_set_compression_options_parallel_threads(self.inner, num);
1204        }
1205    }
1206
1207    /// Sets the compression algorithm that will be used for compressing WAL.
1208    ///
1209    /// At present, only ZSTD compression is supported!
1210    ///
1211    /// Default: `DBCompressionType::None`
1212    ///
1213    /// # Examples
1214    ///
1215    /// ```
1216    /// use rust_rocksdb::{Options, DBCompressionType};
1217    ///
1218    /// let mut opts = Options::default();
1219    /// opts.set_wal_compression_type(DBCompressionType::Zstd);
1220    /// // Or None to disable it
1221    /// opts.set_wal_compression_type(DBCompressionType::None);
1222    /// ```
1223    pub fn set_wal_compression_type(&mut self, t: DBCompressionType) {
1224        match t {
1225            DBCompressionType::None | DBCompressionType::Zstd => unsafe {
1226                ffi::rocksdb_options_set_wal_compression(self.inner, t as c_int);
1227            },
1228            other => unimplemented!("{:?} is not supported for WAL compression", other),
1229        }
1230    }
1231
1232    /// Sets the bottom-most compression algorithm that will be used for
1233    /// compressing blocks at the bottom-most level.
1234    ///
1235    /// Note that to actually enable bottom-most compression configuration after
1236    /// setting the compression type, it needs to be enabled by calling
1237    /// [`set_bottommost_compression_options`](#method.set_bottommost_compression_options) or
1238    /// [`set_bottommost_zstd_max_train_bytes`](#method.set_bottommost_zstd_max_train_bytes) method with `enabled` argument
1239    /// set to `true`.
1240    ///
1241    /// # Examples
1242    ///
1243    /// ```
1244    /// use rust_rocksdb::{Options, DBCompressionType};
1245    ///
1246    /// let mut opts = Options::default();
1247    /// opts.set_bottommost_compression_type(DBCompressionType::Zstd);
1248    /// opts.set_bottommost_zstd_max_train_bytes(0, true);
1249    /// ```
1250    pub fn set_bottommost_compression_type(&mut self, t: DBCompressionType) {
1251        unsafe {
1252            ffi::rocksdb_options_set_bottommost_compression(self.inner, t as c_int);
1253        }
1254    }
1255
1256    /// Different levels can have different compression policies. There
1257    /// are cases where most lower levels would like to use quick compression
1258    /// algorithms while the higher levels (which have more data) use
1259    /// compression algorithms that have better compression but could
1260    /// be slower. This array, if non-empty, should have an entry for
1261    /// each level of the database; these override the value specified in
1262    /// the previous field 'compression'.
1263    ///
1264    /// # Examples
1265    ///
1266    /// ```
1267    /// use rust_rocksdb::{Options, DBCompressionType};
1268    ///
1269    /// let mut opts = Options::default();
1270    /// opts.set_compression_per_level(&[
1271    ///     DBCompressionType::None,
1272    ///     DBCompressionType::None,
1273    ///     DBCompressionType::Snappy,
1274    ///     DBCompressionType::Snappy,
1275    ///     DBCompressionType::Snappy
1276    /// ]);
1277    /// ```
1278    pub fn set_compression_per_level(&mut self, level_types: &[DBCompressionType]) {
1279        unsafe {
1280            let mut level_types: Vec<_> = level_types.iter().map(|&t| t as c_int).collect();
1281            ffi::rocksdb_options_set_compression_per_level(
1282                self.inner,
1283                level_types.as_mut_ptr(),
1284                level_types.len() as size_t,
1285            );
1286        }
1287    }
1288
1289    /// Maximum size of dictionaries used to prime the compression library.
1290    /// Enabling dictionary can improve compression ratios when there are
1291    /// repetitions across data blocks.
1292    ///
1293    /// The dictionary is created by sampling the SST file data. If
1294    /// `zstd_max_train_bytes` is nonzero, the samples are passed through zstd's
1295    /// dictionary generator. Otherwise, the random samples are used directly as
1296    /// the dictionary.
1297    ///
1298    /// When compression dictionary is disabled, we compress and write each block
1299    /// before buffering data for the next one. When compression dictionary is
1300    /// enabled, we buffer all SST file data in-memory so we can sample it, as data
1301    /// can only be compressed and written after the dictionary has been finalized.
1302    /// So users of this feature may see increased memory usage.
1303    ///
1304    /// Default: `0`
1305    ///
1306    /// # Examples
1307    ///
1308    /// ```
1309    /// use rust_rocksdb::Options;
1310    ///
1311    /// let mut opts = Options::default();
1312    /// opts.set_compression_options(4, 5, 6, 7);
1313    /// ```
1314    pub fn set_compression_options(
1315        &mut self,
1316        w_bits: c_int,
1317        level: c_int,
1318        strategy: c_int,
1319        max_dict_bytes: c_int,
1320    ) {
1321        unsafe {
1322            ffi::rocksdb_options_set_compression_options(
1323                self.inner,
1324                w_bits,
1325                level,
1326                strategy,
1327                max_dict_bytes,
1328            );
1329        }
1330    }
1331
1332    /// Sets compression options for blocks at the bottom-most level.  Meaning
1333    /// of all settings is the same as in [`set_compression_options`](#method.set_compression_options) method but
1334    /// affect only the bottom-most compression which is set using
1335    /// [`set_bottommost_compression_type`](#method.set_bottommost_compression_type) method.
1336    ///
1337    /// # Examples
1338    ///
1339    /// ```
1340    /// use rust_rocksdb::{Options, DBCompressionType};
1341    ///
1342    /// let mut opts = Options::default();
1343    /// opts.set_bottommost_compression_type(DBCompressionType::Zstd);
1344    /// opts.set_bottommost_compression_options(4, 5, 6, 7, true);
1345    /// ```
1346    pub fn set_bottommost_compression_options(
1347        &mut self,
1348        w_bits: c_int,
1349        level: c_int,
1350        strategy: c_int,
1351        max_dict_bytes: c_int,
1352        enabled: bool,
1353    ) {
1354        unsafe {
1355            ffi::rocksdb_options_set_bottommost_compression_options(
1356                self.inner,
1357                w_bits,
1358                level,
1359                strategy,
1360                max_dict_bytes,
1361                c_uchar::from(enabled),
1362            );
1363        }
1364    }
1365
1366    /// Sets maximum size of training data passed to zstd's dictionary trainer. Using zstd's
1367    /// dictionary trainer can achieve even better compression ratio improvements than using
1368    /// `max_dict_bytes` alone.
1369    ///
1370    /// The training data will be used to generate a dictionary of max_dict_bytes.
1371    ///
1372    /// Default: 0.
1373    pub fn set_zstd_max_train_bytes(&mut self, value: c_int) {
1374        unsafe {
1375            ffi::rocksdb_options_set_compression_options_zstd_max_train_bytes(self.inner, value);
1376        }
1377    }
1378
1379    /// Sets maximum size of training data passed to zstd's dictionary trainer
1380    /// when compressing the bottom-most level. Using zstd's dictionary trainer
1381    /// can achieve even better compression ratio improvements than using
1382    /// `max_dict_bytes` alone.
1383    ///
1384    /// The training data will be used to generate a dictionary of
1385    /// `max_dict_bytes`.
1386    ///
1387    /// Default: 0.
1388    pub fn set_bottommost_zstd_max_train_bytes(&mut self, value: c_int, enabled: bool) {
1389        unsafe {
1390            ffi::rocksdb_options_set_bottommost_compression_options_zstd_max_train_bytes(
1391                self.inner,
1392                value,
1393                c_uchar::from(enabled),
1394            );
1395        }
1396    }
1397
1398    /// If non-zero, we perform bigger reads when doing compaction. If you're
1399    /// running RocksDB on spinning disks, you should set this to at least 2MB.
1400    /// That way RocksDB's compaction is doing sequential instead of random reads.
1401    ///
1402    /// Default: 2 * 1024 * 1024 (2 MB)
1403    pub fn set_compaction_readahead_size(&mut self, compaction_readahead_size: usize) {
1404        unsafe {
1405            ffi::rocksdb_options_compaction_readahead_size(self.inner, compaction_readahead_size);
1406        }
1407    }
1408
1409    /// Allow RocksDB to pick dynamic base of bytes for levels.
1410    /// With this feature turned on, RocksDB will automatically adjust max bytes for each level.
1411    /// The goal of this feature is to have lower bound on size amplification.
1412    ///
1413    /// Default: false.
1414    pub fn set_level_compaction_dynamic_level_bytes(&mut self, v: bool) {
1415        unsafe {
1416            ffi::rocksdb_options_set_level_compaction_dynamic_level_bytes(
1417                self.inner,
1418                c_uchar::from(v),
1419            );
1420        }
1421    }
1422
1423    /// This option has different meanings for different compaction styles:
1424    ///
1425    /// Leveled: files older than `periodic_compaction_seconds` will be picked up
1426    /// for compaction and will be re-written to the same level as they were
1427    /// before if level_compaction_dynamic_level_bytes is disabled. Otherwise,
1428    /// it will rewrite files to the next level except for the last level files
1429    /// to the same level.
1430    ///
1431    /// FIFO: not supported. Setting this option has no effect for FIFO compaction.
1432    ///
1433    /// Universal: when there are files older than `periodic_compaction_seconds`,
1434    /// rocksdb will try to do as large a compaction as possible including the
1435    /// last level. Such compaction is only skipped if only last level is to
1436    /// be compacted and no file in last level is older than
1437    /// `periodic_compaction_seconds`. See more in
1438    /// UniversalCompactionBuilder::PickPeriodicCompaction().
1439    /// For backward compatibility, the effective value of this option takes
1440    /// into account the value of option `ttl`. The logic is as follows:
1441    ///
1442    /// - both options are set to 30 days if they have the default value.
1443    /// - if both options are zero, zero is picked. Otherwise, we take the min
1444    ///   value among non-zero options values (i.e. takes the stricter limit).
1445    ///
1446    /// One main use of the feature is to make sure a file goes through compaction
1447    /// filters periodically. Users can also use the feature to clear up SST
1448    /// files using old format.
1449    ///
1450    /// A file's age is computed by looking at file_creation_time or creation_time
1451    /// table properties in order, if they have valid non-zero values; if not, the
1452    /// age is based on the file's last modified time (given by the underlying
1453    /// Env).
1454    ///
1455    /// This option only supports block based table format for any compaction
1456    /// style.
1457    ///
1458    /// unit: seconds. Ex: 7 days = 7 * 24 * 60 * 60
1459    ///
1460    /// Values:
1461    /// 0: Turn off Periodic compactions.
1462    /// UINT64_MAX - 1 (0xfffffffffffffffe) is special flag to allow RocksDB to
1463    /// pick default.
1464    ///
1465    /// Default: 30 days if using block based table format + compaction filter +
1466    /// leveled compaction or block based table format + universal compaction.
1467    /// 0 (disabled) otherwise.
1468    ///
1469    pub fn set_periodic_compaction_seconds(&mut self, secs: u64) {
1470        unsafe {
1471            ffi::rocksdb_options_set_periodic_compaction_seconds(self.inner, secs);
1472        }
1473    }
1474
1475    /// When an iterator scans this number of invisible entries (tombstones or
1476    /// hidden puts) from the active memtable during a single iterator operation,
1477    /// we will attempt to flush the memtable. Currently only forward scans are
1478    /// supported (SeekToFirst(), Seek() and Next()).
1479    /// This option helps to reduce the overhead of scanning through a
1480    /// large number of entries in memtable.
1481    /// Users should consider enable deletion-triggered-compaction (see
1482    /// CompactOnDeletionCollectorFactory) together with this option to compact
1483    /// away tombstones after the memtable is flushed.
1484    ///
1485    /// Default: 0 (disabled)
1486    /// Dynamically changeable through the SetOptions() API.
1487    pub fn set_memtable_op_scan_flush_trigger(&mut self, num: u32) {
1488        unsafe {
1489            ffi::rocksdb_options_set_memtable_op_scan_flush_trigger(self.inner, num);
1490        }
1491    }
1492
1493    /// Similar to `memtable_op_scan_flush_trigger`, but this option applies to
1494    /// Next() calls between Seeks or until iterator destruction. If the average
1495    /// of the number of invisible entries scanned from the active memtable, the
1496    /// memtable will be marked for flush.
1497    /// Note that to avoid the case where the window between Seeks is too small,
1498    /// the option only takes effect if the total number of hidden entries scanned
1499    /// within a window is at least `memtable_op_scan_flush_trigger`. So this
1500    /// option is only effective when `memtable_op_scan_flush_trigger` is set.
1501    ///
1502    /// This option should be set to a lower value than
1503    /// `memtable_op_scan_flush_trigger`. It covers the case where an iterator
1504    /// scans through an expensive key range with many invisible entries from the
1505    /// active memtable, but the number of invisible entries per operation does not
1506    /// exceed `memtable_op_scan_flush_trigger`.
1507    ///
1508    /// Default: 0 (disabled)
1509    /// Dynamically changeable through the SetOptions() API.
1510    pub fn set_memtable_avg_op_scan_flush_trigger(&mut self, num: u32) {
1511        unsafe {
1512            ffi::rocksdb_options_set_memtable_avg_op_scan_flush_trigger(self.inner, num);
1513        }
1514    }
1515
1516    /// This option has different meanings for different compaction styles:
1517    ///
1518    /// Leveled: Non-bottom-level files with all keys older than TTL will go
1519    ///    through the compaction process. This usually happens in a cascading
1520    ///    way so that those entries will be compacted to bottommost level/file.
1521    ///    The feature is used to remove stale entries that have been deleted or
1522    ///    updated from the file system.
1523    ///
1524    /// FIFO: Files with all keys older than TTL will be deleted. TTL is only
1525    ///    supported if option max_open_files is set to -1.
1526    ///
1527    /// Universal: users should only set the option `periodic_compaction_seconds`
1528    ///    instead. For backward compatibility, this option has the same
1529    ///    meaning as `periodic_compaction_seconds`. See more in comments for
1530    ///    `periodic_compaction_seconds` on the interaction between these two
1531    ///    options.
1532    ///
1533    /// This option only supports block based table format for any compaction
1534    /// style.
1535    ///
1536    /// unit: seconds. Ex: 1 day = 1 * 24 * 60 * 60
1537    /// 0 means disabling.
1538    /// UINT64_MAX - 1 (0xfffffffffffffffe) is special flag to allow RocksDB to
1539    /// pick default.
1540    ///
1541    /// Default: 30 days if using block based table. 0 (disable) otherwise.
1542    ///
1543    /// Dynamically changeable
1544    /// Note that dynamically changing this option only works for leveled and FIFO
1545    /// compaction. For universal compaction, dynamically changing this option has
1546    /// no effect, users should dynamically change `periodic_compaction_seconds`
1547    /// instead.
1548    pub fn set_ttl(&mut self, secs: u64) {
1549        unsafe {
1550            ffi::rocksdb_options_set_ttl(self.inner, secs);
1551        }
1552    }
1553
1554    pub fn set_merge_operator_associative<F: MergeFn + Clone>(
1555        &mut self,
1556        name: impl CStrLike,
1557        full_merge_fn: F,
1558    ) {
1559        let cb = Box::new(MergeOperatorCallback {
1560            name: name.into_c_string().unwrap(),
1561            full_merge_fn: full_merge_fn.clone(),
1562            partial_merge_fn: full_merge_fn,
1563        });
1564
1565        unsafe {
1566            let mo = ffi::rocksdb_mergeoperator_create(
1567                Box::into_raw(cb).cast::<c_void>(),
1568                Some(merge_operator::destructor_callback::<F, F>),
1569                Some(full_merge_callback::<F, F>),
1570                Some(partial_merge_callback::<F, F>),
1571                Some(merge_operator::delete_callback),
1572                Some(merge_operator::name_callback::<F, F>),
1573            );
1574            ffi::rocksdb_options_set_merge_operator(self.inner, mo);
1575        }
1576    }
1577
1578    pub fn set_merge_operator<F: MergeFn, PF: MergeFn>(
1579        &mut self,
1580        name: impl CStrLike,
1581        full_merge_fn: F,
1582        partial_merge_fn: PF,
1583    ) {
1584        let cb = Box::new(MergeOperatorCallback {
1585            name: name.into_c_string().unwrap(),
1586            full_merge_fn,
1587            partial_merge_fn,
1588        });
1589
1590        unsafe {
1591            let mo = ffi::rocksdb_mergeoperator_create(
1592                Box::into_raw(cb).cast::<c_void>(),
1593                Some(merge_operator::destructor_callback::<F, PF>),
1594                Some(full_merge_callback::<F, PF>),
1595                Some(partial_merge_callback::<F, PF>),
1596                Some(merge_operator::delete_callback),
1597                Some(merge_operator::name_callback::<F, PF>),
1598            );
1599            ffi::rocksdb_options_set_merge_operator(self.inner, mo);
1600        }
1601    }
1602
1603    #[deprecated(
1604        since = "0.5.0",
1605        note = "add_merge_operator has been renamed to set_merge_operator"
1606    )]
1607    pub fn add_merge_operator<F: MergeFn + Clone>(&mut self, name: &str, merge_fn: F) {
1608        self.set_merge_operator_associative(name, merge_fn);
1609    }
1610
1611    /// Sets a compaction filter used to determine if entries should be kept, changed,
1612    /// or removed during compaction.
1613    ///
1614    /// An example use case is to remove entries with an expired TTL.
1615    ///
1616    /// If you take a snapshot of the database, only values written since the last
1617    /// snapshot will be passed through the compaction filter.
1618    ///
1619    /// If multi-threaded compaction is used, `filter_fn` may be called multiple times
1620    /// simultaneously.
1621    pub fn set_compaction_filter<F>(&mut self, name: impl CStrLike, filter_fn: F)
1622    where
1623        F: CompactionFilterFn + Send + 'static,
1624    {
1625        let cb = Box::new(CompactionFilterCallback {
1626            name: name.into_c_string().unwrap(),
1627            filter_fn,
1628        });
1629
1630        unsafe {
1631            let cf = ffi::rocksdb_compactionfilter_create(
1632                Box::into_raw(cb).cast::<c_void>(),
1633                Some(compaction_filter::destructor_callback::<CompactionFilterCallback<F>>),
1634                Some(compaction_filter::filter_callback::<CompactionFilterCallback<F>>),
1635                Some(compaction_filter::name_callback::<CompactionFilterCallback<F>>),
1636            );
1637            ffi::rocksdb_options_set_compaction_filter(self.inner, cf);
1638        }
1639    }
1640
1641    pub fn add_event_listener<L: EventListener>(&mut self, l: L) {
1642        let handle = new_event_listener(l);
1643        unsafe { ffi::rocksdb_options_add_eventlistener(self.inner, handle.inner) }
1644    }
1645
1646    /// This is a factory that provides compaction filter objects which allow
1647    /// an application to modify/delete a key-value during background compaction.
1648    ///
1649    /// A new filter will be created on each compaction run.  If multithreaded
1650    /// compaction is being used, each created CompactionFilter will only be used
1651    /// from a single thread and so does not need to be thread-safe.
1652    ///
1653    /// Default: nullptr
1654    pub fn set_compaction_filter_factory<F>(&mut self, factory: F)
1655    where
1656        F: CompactionFilterFactory + 'static,
1657    {
1658        let factory = Box::new(factory);
1659
1660        unsafe {
1661            let cff = ffi::rocksdb_compactionfilterfactory_create(
1662                Box::into_raw(factory).cast::<c_void>(),
1663                Some(compaction_filter_factory::destructor_callback::<F>),
1664                Some(compaction_filter_factory::create_compaction_filter_callback::<F>),
1665                Some(compaction_filter_factory::name_callback::<F>),
1666            );
1667
1668            ffi::rocksdb_options_set_compaction_filter_factory(self.inner, cff);
1669        }
1670    }
1671
1672    /// Sets the comparator used to define the order of keys in the table.
1673    /// Default: a comparator that uses lexicographic byte-wise ordering
1674    ///
1675    /// The client must ensure that the comparator supplied here has the same
1676    /// name and orders keys *exactly* the same as the comparator provided to
1677    /// previous open calls on the same DB.
1678    pub fn set_comparator(&mut self, name: impl CStrLike, compare_fn: Box<CompareFn>) {
1679        let cb = Box::new(ComparatorCallback {
1680            name: name.into_c_string().unwrap(),
1681            compare_fn,
1682        });
1683
1684        unsafe {
1685            let cmp = ffi::rocksdb_comparator_create(
1686                Box::into_raw(cb).cast::<c_void>(),
1687                Some(ComparatorCallback::destructor_callback),
1688                Some(ComparatorCallback::compare_callback),
1689                Some(ComparatorCallback::name_callback),
1690            );
1691            ffi::rocksdb_options_set_comparator(self.inner, cmp);
1692        }
1693    }
1694
1695    /// Sets the comparator that are timestamp-aware, used to define the order of keys in the table,
1696    /// taking timestamp into consideration.
1697    /// Find more information on timestamp-aware comparator on [here](https://github.com/facebook/rocksdb/wiki/User-defined-Timestamp)
1698    ///
1699    /// The client must ensure that the comparator supplied here has the same
1700    /// name and orders keys *exactly* the same as the comparator provided to
1701    /// previous open calls on the same DB.
1702    pub fn set_comparator_with_ts(
1703        &mut self,
1704        name: impl CStrLike,
1705        timestamp_size: usize,
1706        compare_fn: Box<CompareFn>,
1707        compare_ts_fn: Box<CompareTsFn>,
1708        compare_without_ts_fn: Box<CompareWithoutTsFn>,
1709    ) {
1710        let cb = Box::new(ComparatorWithTsCallback {
1711            name: name.into_c_string().unwrap(),
1712            compare_fn,
1713            compare_ts_fn,
1714            compare_without_ts_fn,
1715        });
1716
1717        unsafe {
1718            let cmp = ffi::rocksdb_comparator_with_ts_create(
1719                Box::into_raw(cb).cast::<c_void>(),
1720                Some(ComparatorWithTsCallback::destructor_callback),
1721                Some(ComparatorWithTsCallback::compare_callback),
1722                Some(ComparatorWithTsCallback::compare_ts_callback),
1723                Some(ComparatorWithTsCallback::compare_without_ts_callback),
1724                Some(ComparatorWithTsCallback::name_callback),
1725                timestamp_size,
1726            );
1727            ffi::rocksdb_options_set_comparator(self.inner, cmp);
1728        }
1729    }
1730
1731    pub fn set_prefix_extractor(&mut self, prefix_extractor: SliceTransform) {
1732        unsafe {
1733            ffi::rocksdb_options_set_prefix_extractor(self.inner, prefix_extractor.inner);
1734        }
1735    }
1736
1737    // Use this if you don't need to keep the data sorted, i.e. you'll never use
1738    // an iterator, only Put() and Get() API calls
1739    //
1740    pub fn optimize_for_point_lookup(&mut self, block_cache_size_mb: u64) {
1741        unsafe {
1742            ffi::rocksdb_options_optimize_for_point_lookup(self.inner, block_cache_size_mb);
1743        }
1744    }
1745
1746    /// Sets the optimize_filters_for_hits flag
1747    ///
1748    /// Default: `false`
1749    ///
1750    /// # Examples
1751    ///
1752    /// ```
1753    /// use rust_rocksdb::Options;
1754    ///
1755    /// let mut opts = Options::default();
1756    /// opts.set_optimize_filters_for_hits(true);
1757    /// ```
1758    pub fn set_optimize_filters_for_hits(&mut self, optimize_for_hits: bool) {
1759        unsafe {
1760            ffi::rocksdb_options_set_optimize_filters_for_hits(
1761                self.inner,
1762                c_int::from(optimize_for_hits),
1763            );
1764        }
1765    }
1766
1767    /// Sets the periodicity when obsolete files get deleted.
1768    ///
1769    /// The files that get out of scope by compaction
1770    /// process will still get automatically delete on every compaction,
1771    /// regardless of this setting.
1772    ///
1773    /// Default: 6 hours
1774    pub fn set_delete_obsolete_files_period_micros(&mut self, micros: u64) {
1775        unsafe {
1776            ffi::rocksdb_options_set_delete_obsolete_files_period_micros(self.inner, micros);
1777        }
1778    }
1779
1780    /// Prepare the DB for bulk loading.
1781    ///
1782    /// All data will be in level 0 without any automatic compaction.
1783    /// It's recommended to manually call CompactRange(NULL, NULL) before reading
1784    /// from the database, because otherwise the read can be very slow.
1785    pub fn prepare_for_bulk_load(&mut self) {
1786        unsafe {
1787            ffi::rocksdb_options_prepare_for_bulk_load(self.inner);
1788        }
1789    }
1790
1791    /// Sets the number of open files that can be used by the DB. You may need to
1792    /// increase this if your database has a large working set. Value `-1` means
1793    /// files opened are always kept open. You can estimate number of files based
1794    /// on target_file_size_base and target_file_size_multiplier for level-based
1795    /// compaction. For universal-style compaction, you can usually set it to `-1`.
1796    ///
1797    /// Default: `-1`
1798    ///
1799    /// # Examples
1800    ///
1801    /// ```
1802    /// use rust_rocksdb::Options;
1803    ///
1804    /// let mut opts = Options::default();
1805    /// opts.set_max_open_files(10);
1806    /// ```
1807    pub fn set_max_open_files(&mut self, nfiles: c_int) {
1808        unsafe {
1809            ffi::rocksdb_options_set_max_open_files(self.inner, nfiles);
1810        }
1811    }
1812
1813    /// If max_open_files is -1, DB will open all files on DB::Open(). You can
1814    /// use this option to increase the number of threads used to open the files.
1815    /// Default: 16
1816    pub fn set_max_file_opening_threads(&mut self, nthreads: c_int) {
1817        unsafe {
1818            ffi::rocksdb_options_set_max_file_opening_threads(self.inner, nthreads);
1819        }
1820    }
1821
1822    /// By default, writes to stable storage use fdatasync (on platforms
1823    /// where this function is available). If this option is true,
1824    /// fsync is used instead.
1825    ///
1826    /// fsync and fdatasync are equally safe for our purposes and fdatasync is
1827    /// faster, so it is rarely necessary to set this option. It is provided
1828    /// as a workaround for kernel/filesystem bugs, such as one that affected
1829    /// fdatasync with ext4 in kernel versions prior to 3.7.
1830    ///
1831    /// Default: `false`
1832    ///
1833    /// # Examples
1834    ///
1835    /// ```
1836    /// use rust_rocksdb::Options;
1837    ///
1838    /// let mut opts = Options::default();
1839    /// opts.set_use_fsync(true);
1840    /// ```
1841    pub fn set_use_fsync(&mut self, useit: bool) {
1842        unsafe {
1843            ffi::rocksdb_options_set_use_fsync(self.inner, c_int::from(useit));
1844        }
1845    }
1846
1847    /// Returns the value of the `use_fsync` option.
1848    pub fn get_use_fsync(&self) -> bool {
1849        let val = unsafe { ffi::rocksdb_options_get_use_fsync(self.inner) };
1850        val != 0
1851    }
1852
1853    /// Specifies the absolute info LOG dir.
1854    ///
1855    /// If it is empty, the log files will be in the same dir as data.
1856    /// If it is non empty, the log files will be in the specified dir,
1857    /// and the db data dir's absolute path will be used as the log file
1858    /// name's prefix.
1859    ///
1860    /// Default: empty
1861    pub fn set_db_log_dir<P: AsRef<Path>>(&mut self, path: P) {
1862        let p = to_cpath(path).unwrap();
1863        unsafe {
1864            ffi::rocksdb_options_set_db_log_dir(self.inner, p.as_ptr());
1865        }
1866    }
1867
1868    /// Specifies the log level.
1869    /// Consider the `LogLevel` enum for a list of possible levels.
1870    ///
1871    /// Default: Info
1872    ///
1873    /// # Examples
1874    ///
1875    /// ```
1876    /// use rust_rocksdb::{Options, LogLevel};
1877    ///
1878    /// let mut opts = Options::default();
1879    /// opts.set_log_level(LogLevel::Warn);
1880    /// ```
1881    pub fn set_log_level(&mut self, level: LogLevel) {
1882        unsafe {
1883            ffi::rocksdb_options_set_info_log_level(self.inner, level as c_int);
1884        }
1885    }
1886
1887    /// Allows OS to incrementally sync files to disk while they are being
1888    /// written, asynchronously, in the background. This operation can be used
1889    /// to smooth out write I/Os over time. Users shouldn't rely on it for
1890    /// persistency guarantee.
1891    /// Issue one request for every bytes_per_sync written. `0` turns it off.
1892    ///
1893    /// Default: `0`
1894    ///
1895    /// You may consider using rate_limiter to regulate write rate to device.
1896    /// When rate limiter is enabled, it automatically enables bytes_per_sync
1897    /// to 1MB.
1898    ///
1899    /// This option applies to table files
1900    ///
1901    /// # Examples
1902    ///
1903    /// ```
1904    /// use rust_rocksdb::Options;
1905    ///
1906    /// let mut opts = Options::default();
1907    /// opts.set_bytes_per_sync(1024 * 1024);
1908    /// ```
1909    pub fn set_bytes_per_sync(&mut self, nbytes: u64) {
1910        unsafe {
1911            ffi::rocksdb_options_set_bytes_per_sync(self.inner, nbytes);
1912        }
1913    }
1914
1915    /// Same as bytes_per_sync, but applies to WAL files.
1916    ///
1917    /// Default: 0, turned off
1918    ///
1919    /// Dynamically changeable through SetDBOptions() API.
1920    pub fn set_wal_bytes_per_sync(&mut self, nbytes: u64) {
1921        unsafe {
1922            ffi::rocksdb_options_set_wal_bytes_per_sync(self.inner, nbytes);
1923        }
1924    }
1925
1926    /// Sets the maximum buffer size that is used by WritableFileWriter.
1927    ///
1928    /// On Windows, we need to maintain an aligned buffer for writes.
1929    /// We allow the buffer to grow until it's size hits the limit in buffered
1930    /// IO and fix the buffer size when using direct IO to ensure alignment of
1931    /// write requests if the logical sector size is unusual
1932    ///
1933    /// Default: 1024 * 1024 (1 MB)
1934    ///
1935    /// Dynamically changeable through SetDBOptions() API.
1936    pub fn set_writable_file_max_buffer_size(&mut self, nbytes: u64) {
1937        unsafe {
1938            ffi::rocksdb_options_set_writable_file_max_buffer_size(self.inner, nbytes);
1939        }
1940    }
1941
1942    /// If true, allow multi-writers to update mem tables in parallel.
1943    /// Only some memtable_factory-s support concurrent writes; currently it
1944    /// is implemented only for SkipListFactory.  Concurrent memtable writes
1945    /// are not compatible with inplace_update_support or filter_deletes.
1946    /// It is strongly recommended to set enable_write_thread_adaptive_yield
1947    /// if you are going to use this feature.
1948    ///
1949    /// Default: true
1950    ///
1951    /// # Examples
1952    ///
1953    /// ```
1954    /// use rust_rocksdb::Options;
1955    ///
1956    /// let mut opts = Options::default();
1957    /// opts.set_allow_concurrent_memtable_write(false);
1958    /// ```
1959    pub fn set_allow_concurrent_memtable_write(&mut self, allow: bool) {
1960        unsafe {
1961            ffi::rocksdb_options_set_allow_concurrent_memtable_write(
1962                self.inner,
1963                c_uchar::from(allow),
1964            );
1965        }
1966    }
1967
1968    /// If true, threads synchronizing with the write batch group leader will wait for up to
1969    /// write_thread_max_yield_usec before blocking on a mutex. This can substantially improve
1970    /// throughput for concurrent workloads, regardless of whether allow_concurrent_memtable_write
1971    /// is enabled.
1972    ///
1973    /// Default: true
1974    pub fn set_enable_write_thread_adaptive_yield(&mut self, enabled: bool) {
1975        unsafe {
1976            ffi::rocksdb_options_set_enable_write_thread_adaptive_yield(
1977                self.inner,
1978                c_uchar::from(enabled),
1979            );
1980        }
1981    }
1982
1983    /// Specifies whether an iteration->Next() sequentially skips over keys with the same user-key or not.
1984    ///
1985    /// This number specifies the number of keys (with the same userkey)
1986    /// that will be sequentially skipped before a reseek is issued.
1987    ///
1988    /// Default: 8
1989    pub fn set_max_sequential_skip_in_iterations(&mut self, num: u64) {
1990        unsafe {
1991            ffi::rocksdb_options_set_max_sequential_skip_in_iterations(self.inner, num);
1992        }
1993    }
1994
1995    /// Enable direct I/O mode for reading
1996    /// they may or may not improve performance depending on the use case
1997    ///
1998    /// Files will be opened in "direct I/O" mode
1999    /// which means that data read from the disk will not be cached or
2000    /// buffered. The hardware buffer of the devices may however still
2001    /// be used. Memory mapped files are not impacted by these parameters.
2002    ///
2003    /// Default: false
2004    ///
2005    /// # Examples
2006    ///
2007    /// ```
2008    /// use rust_rocksdb::Options;
2009    ///
2010    /// let mut opts = Options::default();
2011    /// opts.set_use_direct_reads(true);
2012    /// ```
2013    pub fn set_use_direct_reads(&mut self, enabled: bool) {
2014        unsafe {
2015            ffi::rocksdb_options_set_use_direct_reads(self.inner, c_uchar::from(enabled));
2016        }
2017    }
2018
2019    /// Enable direct I/O mode for flush and compaction
2020    ///
2021    /// Files will be opened in "direct I/O" mode
2022    /// which means that data written to the disk will not be cached or
2023    /// buffered. The hardware buffer of the devices may however still
2024    /// be used. Memory mapped files are not impacted by these parameters.
2025    /// they may or may not improve performance depending on the use case
2026    ///
2027    /// Default: false
2028    ///
2029    /// # Examples
2030    ///
2031    /// ```
2032    /// use rust_rocksdb::Options;
2033    ///
2034    /// let mut opts = Options::default();
2035    /// opts.set_use_direct_io_for_flush_and_compaction(true);
2036    /// ```
2037    pub fn set_use_direct_io_for_flush_and_compaction(&mut self, enabled: bool) {
2038        unsafe {
2039            ffi::rocksdb_options_set_use_direct_io_for_flush_and_compaction(
2040                self.inner,
2041                c_uchar::from(enabled),
2042            );
2043        }
2044    }
2045
2046    /// Enable/disable child process inherit open files.
2047    ///
2048    /// Default: true
2049    pub fn set_is_fd_close_on_exec(&mut self, enabled: bool) {
2050        unsafe {
2051            ffi::rocksdb_options_set_is_fd_close_on_exec(self.inner, c_uchar::from(enabled));
2052        }
2053    }
2054
2055    /// Hints to the OS that it should not buffer disk I/O. Enabling this
2056    /// parameter may improve performance but increases pressure on the
2057    /// system cache.
2058    ///
2059    /// The exact behavior of this parameter is platform dependent.
2060    ///
2061    /// On POSIX systems, after RocksDB reads data from disk it will
2062    /// mark the pages as "unneeded". The operating system may or may not
2063    /// evict these pages from memory, reducing pressure on the system
2064    /// cache. If the disk block is requested again this can result in
2065    /// additional disk I/O.
2066    ///
2067    /// On WINDOWS systems, files will be opened in "unbuffered I/O" mode
2068    /// which means that data read from the disk will not be cached or
2069    /// bufferized. The hardware buffer of the devices may however still
2070    /// be used. Memory mapped files are not impacted by this parameter.
2071    ///
2072    /// Default: true
2073    ///
2074    /// # Examples
2075    ///
2076    /// ```
2077    /// use rust_rocksdb::Options;
2078    ///
2079    /// let mut opts = Options::default();
2080    /// #[allow(deprecated)]
2081    /// opts.set_allow_os_buffer(false);
2082    /// ```
2083    #[deprecated(
2084        since = "0.7.0",
2085        note = "replaced with set_use_direct_reads/set_use_direct_io_for_flush_and_compaction methods"
2086    )]
2087    pub fn set_allow_os_buffer(&mut self, is_allow: bool) {
2088        self.set_use_direct_reads(!is_allow);
2089        self.set_use_direct_io_for_flush_and_compaction(!is_allow);
2090    }
2091
2092    /// Sets the number of shards used for table cache.
2093    ///
2094    /// Default: `6`
2095    ///
2096    /// # Examples
2097    ///
2098    /// ```
2099    /// use rust_rocksdb::Options;
2100    ///
2101    /// let mut opts = Options::default();
2102    /// opts.set_table_cache_num_shard_bits(4);
2103    /// ```
2104    pub fn set_table_cache_num_shard_bits(&mut self, nbits: c_int) {
2105        unsafe {
2106            ffi::rocksdb_options_set_table_cache_numshardbits(self.inner, nbits);
2107        }
2108    }
2109
2110    /// By default target_file_size_multiplier is 1, which means
2111    /// by default files in different levels will have similar size.
2112    ///
2113    /// Dynamically changeable through SetOptions() API
2114    pub fn set_target_file_size_multiplier(&mut self, multiplier: i32) {
2115        unsafe {
2116            ffi::rocksdb_options_set_target_file_size_multiplier(self.inner, multiplier as c_int);
2117        }
2118    }
2119
2120    /// Sets the minimum number of write buffers that will be merged
2121    /// before writing to storage.  If set to `1`, then
2122    /// all write buffers are flushed to L0 as individual files and this increases
2123    /// read amplification because a get request has to check in all of these
2124    /// files. Also, an in-memory merge may result in writing lesser
2125    /// data to storage if there are duplicate records in each of these
2126    /// individual write buffers.
2127    ///
2128    /// Default: `1`
2129    ///
2130    /// # Examples
2131    ///
2132    /// ```
2133    /// use rust_rocksdb::Options;
2134    ///
2135    /// let mut opts = Options::default();
2136    /// opts.set_min_write_buffer_number(2);
2137    /// ```
2138    pub fn set_min_write_buffer_number(&mut self, nbuf: c_int) {
2139        unsafe {
2140            ffi::rocksdb_options_set_min_write_buffer_number_to_merge(self.inner, nbuf);
2141        }
2142    }
2143
2144    /// Sets the maximum number of write buffers that are built up in memory.
2145    /// The default and the minimum number is 2, so that when 1 write buffer
2146    /// is being flushed to storage, new writes can continue to the other
2147    /// write buffer.
2148    /// If max_write_buffer_number > 3, writing will be slowed down to
2149    /// options.delayed_write_rate if we are writing to the last write buffer
2150    /// allowed.
2151    ///
2152    /// Default: `2`
2153    ///
2154    /// # Examples
2155    ///
2156    /// ```
2157    /// use rust_rocksdb::Options;
2158    ///
2159    /// let mut opts = Options::default();
2160    /// opts.set_max_write_buffer_number(4);
2161    /// ```
2162    pub fn set_max_write_buffer_number(&mut self, nbuf: c_int) {
2163        unsafe {
2164            ffi::rocksdb_options_set_max_write_buffer_number(self.inner, nbuf);
2165        }
2166    }
2167
2168    /// Sets the amount of data to build up in memory (backed by an unsorted log
2169    /// on disk) before converting to a sorted on-disk file.
2170    ///
2171    /// Larger values increase performance, especially during bulk loads.
2172    /// Up to max_write_buffer_number write buffers may be held in memory
2173    /// at the same time,
2174    /// so you may wish to adjust this parameter to control memory usage.
2175    /// Also, a larger write buffer will result in a longer recovery time
2176    /// the next time the database is opened.
2177    ///
2178    /// Note that write_buffer_size is enforced per column family.
2179    /// See db_write_buffer_size for sharing memory across column families.
2180    ///
2181    /// Default: `0x4000000` (64MiB)
2182    ///
2183    /// Dynamically changeable through SetOptions() API
2184    ///
2185    /// # Examples
2186    ///
2187    /// ```
2188    /// use rust_rocksdb::Options;
2189    ///
2190    /// let mut opts = Options::default();
2191    /// opts.set_write_buffer_size(128 * 1024 * 1024);
2192    /// ```
2193    pub fn set_write_buffer_size(&mut self, size: usize) {
2194        unsafe {
2195            ffi::rocksdb_options_set_write_buffer_size(self.inner, size);
2196        }
2197    }
2198
2199    /// Amount of data to build up in memtables across all column
2200    /// families before writing to disk.
2201    ///
2202    /// This is distinct from write_buffer_size, which enforces a limit
2203    /// for a single memtable.
2204    ///
2205    /// This feature is disabled by default. Specify a non-zero value
2206    /// to enable it.
2207    ///
2208    /// Default: 0 (disabled)
2209    ///
2210    /// # Examples
2211    ///
2212    /// ```
2213    /// use rust_rocksdb::Options;
2214    ///
2215    /// let mut opts = Options::default();
2216    /// opts.set_db_write_buffer_size(128 * 1024 * 1024);
2217    /// ```
2218    pub fn set_db_write_buffer_size(&mut self, size: usize) {
2219        unsafe {
2220            ffi::rocksdb_options_set_db_write_buffer_size(self.inner, size);
2221        }
2222    }
2223
2224    /// Control maximum total data size for a level.
2225    /// max_bytes_for_level_base is the max total for level-1.
2226    /// Maximum number of bytes for level L can be calculated as
2227    /// (max_bytes_for_level_base) * (max_bytes_for_level_multiplier ^ (L-1))
2228    /// For example, if max_bytes_for_level_base is 200MB, and if
2229    /// max_bytes_for_level_multiplier is 10, total data size for level-1
2230    /// will be 200MB, total file size for level-2 will be 2GB,
2231    /// and total file size for level-3 will be 20GB.
2232    ///
2233    /// Default: `0x10000000` (256MiB).
2234    ///
2235    /// Dynamically changeable through SetOptions() API
2236    ///
2237    /// # Examples
2238    ///
2239    /// ```
2240    /// use rust_rocksdb::Options;
2241    ///
2242    /// let mut opts = Options::default();
2243    /// opts.set_max_bytes_for_level_base(512 * 1024 * 1024);
2244    /// ```
2245    pub fn set_max_bytes_for_level_base(&mut self, size: u64) {
2246        unsafe {
2247            ffi::rocksdb_options_set_max_bytes_for_level_base(self.inner, size);
2248        }
2249    }
2250
2251    /// Default: `10`
2252    ///
2253    /// # Examples
2254    ///
2255    /// ```
2256    /// use rust_rocksdb::Options;
2257    ///
2258    /// let mut opts = Options::default();
2259    /// opts.set_max_bytes_for_level_multiplier(4.0);
2260    /// ```
2261    pub fn set_max_bytes_for_level_multiplier(&mut self, mul: f64) {
2262        unsafe {
2263            ffi::rocksdb_options_set_max_bytes_for_level_multiplier(self.inner, mul);
2264        }
2265    }
2266
2267    /// The manifest file is rolled over on reaching this limit.
2268    /// The older manifest file be deleted.
2269    /// The default value is MAX_INT so that roll-over does not take place.
2270    ///
2271    /// # Examples
2272    ///
2273    /// ```
2274    /// use rust_rocksdb::Options;
2275    ///
2276    /// let mut opts = Options::default();
2277    /// opts.set_max_manifest_file_size(20 * 1024 * 1024);
2278    /// ```
2279    pub fn set_max_manifest_file_size(&mut self, size: usize) {
2280        unsafe {
2281            ffi::rocksdb_options_set_max_manifest_file_size(self.inner, size);
2282        }
2283    }
2284
2285    /// Sets the target file size for compaction.
2286    /// target_file_size_base is per-file size for level-1.
2287    /// Target file size for level L can be calculated by
2288    /// target_file_size_base * (target_file_size_multiplier ^ (L-1))
2289    /// For example, if target_file_size_base is 2MB and
2290    /// target_file_size_multiplier is 10, then each file on level-1 will
2291    /// be 2MB, and each file on level 2 will be 20MB,
2292    /// and each file on level-3 will be 200MB.
2293    ///
2294    /// Default: `0x4000000` (64MiB)
2295    ///
2296    /// Dynamically changeable through SetOptions() API
2297    ///
2298    /// # Examples
2299    ///
2300    /// ```
2301    /// use rust_rocksdb::Options;
2302    ///
2303    /// let mut opts = Options::default();
2304    /// opts.set_target_file_size_base(128 * 1024 * 1024);
2305    /// ```
2306    pub fn set_target_file_size_base(&mut self, size: u64) {
2307        unsafe {
2308            ffi::rocksdb_options_set_target_file_size_base(self.inner, size);
2309        }
2310    }
2311
2312    /// Sets the minimum number of write buffers that will be merged together
2313    /// before writing to storage.  If set to `1`, then
2314    /// all write buffers are flushed to L0 as individual files and this increases
2315    /// read amplification because a get request has to check in all of these
2316    /// files. Also, an in-memory merge may result in writing lesser
2317    /// data to storage if there are duplicate records in each of these
2318    /// individual write buffers.
2319    ///
2320    /// Default: `1`
2321    ///
2322    /// # Examples
2323    ///
2324    /// ```
2325    /// use rust_rocksdb::Options;
2326    ///
2327    /// let mut opts = Options::default();
2328    /// opts.set_min_write_buffer_number_to_merge(2);
2329    /// ```
2330    pub fn set_min_write_buffer_number_to_merge(&mut self, to_merge: c_int) {
2331        unsafe {
2332            ffi::rocksdb_options_set_min_write_buffer_number_to_merge(self.inner, to_merge);
2333        }
2334    }
2335
2336    /// Sets the number of files to trigger level-0 compaction. A value < `0` means that
2337    /// level-0 compaction will not be triggered by number of files at all.
2338    ///
2339    /// Default: `4`
2340    ///
2341    /// Dynamically changeable through SetOptions() API
2342    ///
2343    /// # Examples
2344    ///
2345    /// ```
2346    /// use rust_rocksdb::Options;
2347    ///
2348    /// let mut opts = Options::default();
2349    /// opts.set_level_zero_file_num_compaction_trigger(8);
2350    /// ```
2351    pub fn set_level_zero_file_num_compaction_trigger(&mut self, n: c_int) {
2352        unsafe {
2353            ffi::rocksdb_options_set_level0_file_num_compaction_trigger(self.inner, n);
2354        }
2355    }
2356
2357    /// Sets the soft limit on number of level-0 files. We start slowing down writes at this
2358    /// point. A value < `0` means that no writing slowdown will be triggered by
2359    /// number of files in level-0.
2360    ///
2361    /// Default: `20`
2362    ///
2363    /// Dynamically changeable through SetOptions() API
2364    ///
2365    /// # Examples
2366    ///
2367    /// ```
2368    /// use rust_rocksdb::Options;
2369    ///
2370    /// let mut opts = Options::default();
2371    /// opts.set_level_zero_slowdown_writes_trigger(10);
2372    /// ```
2373    pub fn set_level_zero_slowdown_writes_trigger(&mut self, n: c_int) {
2374        unsafe {
2375            ffi::rocksdb_options_set_level0_slowdown_writes_trigger(self.inner, n);
2376        }
2377    }
2378
2379    /// Sets the maximum number of level-0 files.  We stop writes at this point.
2380    ///
2381    /// Default: `24`
2382    ///
2383    /// Dynamically changeable through SetOptions() API
2384    ///
2385    /// # Examples
2386    ///
2387    /// ```
2388    /// use rust_rocksdb::Options;
2389    ///
2390    /// let mut opts = Options::default();
2391    /// opts.set_level_zero_stop_writes_trigger(48);
2392    /// ```
2393    pub fn set_level_zero_stop_writes_trigger(&mut self, n: c_int) {
2394        unsafe {
2395            ffi::rocksdb_options_set_level0_stop_writes_trigger(self.inner, n);
2396        }
2397    }
2398
2399    /// Sets the compaction style.
2400    ///
2401    /// Default: DBCompactionStyle::Level
2402    ///
2403    /// # Examples
2404    ///
2405    /// ```
2406    /// use rust_rocksdb::{Options, DBCompactionStyle};
2407    ///
2408    /// let mut opts = Options::default();
2409    /// opts.set_compaction_style(DBCompactionStyle::Universal);
2410    /// ```
2411    pub fn set_compaction_style(&mut self, style: DBCompactionStyle) {
2412        unsafe {
2413            ffi::rocksdb_options_set_compaction_style(self.inner, style as c_int);
2414        }
2415    }
2416
2417    /// Sets the options needed to support Universal Style compactions.
2418    pub fn set_universal_compaction_options(&mut self, uco: &UniversalCompactOptions) {
2419        unsafe {
2420            ffi::rocksdb_options_set_universal_compaction_options(self.inner, uco.inner);
2421        }
2422    }
2423
2424    /// Sets the options for FIFO compaction style.
2425    pub fn set_fifo_compaction_options(&mut self, fco: &FifoCompactOptions) {
2426        unsafe {
2427            ffi::rocksdb_options_set_fifo_compaction_options(self.inner, fco.inner);
2428        }
2429    }
2430
2431    /// Sets unordered_write to true trades higher write throughput with
2432    /// relaxing the immutability guarantee of snapshots. This violates the
2433    /// repeatability one expects from ::Get from a snapshot, as well as
2434    /// ::MultiGet and Iterator's consistent-point-in-time view property.
2435    /// If the application cannot tolerate the relaxed guarantees, it can implement
2436    /// its own mechanisms to work around that and yet benefit from the higher
2437    /// throughput. Using TransactionDB with WRITE_PREPARED write policy and
2438    /// two_write_queues=true is one way to achieve immutable snapshots despite
2439    /// unordered_write.
2440    ///
2441    /// By default, i.e., when it is false, rocksdb does not advance the sequence
2442    /// number for new snapshots unless all the writes with lower sequence numbers
2443    /// are already finished. This provides the immutability that we expect from
2444    /// snapshots. Moreover, since Iterator and MultiGet internally depend on
2445    /// snapshots, the snapshot immutability results into Iterator and MultiGet
2446    /// offering consistent-point-in-time view. If set to true, although
2447    /// Read-Your-Own-Write property is still provided, the snapshot immutability
2448    /// property is relaxed: the writes issued after the snapshot is obtained (with
2449    /// larger sequence numbers) will be still not visible to the reads from that
2450    /// snapshot, however, there still might be pending writes (with lower sequence
2451    /// number) that will change the state visible to the snapshot after they are
2452    /// landed to the memtable.
2453    ///
2454    /// Default: false
2455    pub fn set_unordered_write(&mut self, unordered: bool) {
2456        unsafe {
2457            ffi::rocksdb_options_set_unordered_write(self.inner, c_uchar::from(unordered));
2458        }
2459    }
2460
2461    /// Sets maximum number of threads that will
2462    /// concurrently perform a compaction job by breaking it into multiple,
2463    /// smaller ones that are run simultaneously.
2464    ///
2465    /// Default: 1 (i.e. no subcompactions)
2466    pub fn set_max_subcompactions(&mut self, num: u32) {
2467        unsafe {
2468            ffi::rocksdb_options_set_max_subcompactions(self.inner, num);
2469        }
2470    }
2471
2472    /// Sets maximum number of concurrent background jobs
2473    /// (compactions and flushes).
2474    ///
2475    /// Default: 2
2476    ///
2477    /// Dynamically changeable through SetDBOptions() API.
2478    pub fn set_max_background_jobs(&mut self, jobs: c_int) {
2479        unsafe {
2480            ffi::rocksdb_options_set_max_background_jobs(self.inner, jobs);
2481        }
2482    }
2483
2484    /// Sets the maximum number of concurrent background compaction jobs, submitted to
2485    /// the default LOW priority thread pool.
2486    /// We first try to schedule compactions based on
2487    /// `base_background_compactions`. If the compaction cannot catch up , we
2488    /// will increase number of compaction threads up to
2489    /// `max_background_compactions`.
2490    ///
2491    /// If you're increasing this, also consider increasing number of threads in
2492    /// LOW priority thread pool. For more information, see
2493    /// Env::SetBackgroundThreads
2494    ///
2495    /// Default: `1`
2496    ///
2497    /// # Examples
2498    ///
2499    /// ```
2500    /// use rust_rocksdb::Options;
2501    ///
2502    /// let mut opts = Options::default();
2503    /// #[allow(deprecated)]
2504    /// opts.set_max_background_compactions(2);
2505    /// ```
2506    #[deprecated(
2507        since = "0.15.0",
2508        note = "RocksDB automatically decides this based on the value of max_background_jobs"
2509    )]
2510    pub fn set_max_background_compactions(&mut self, n: c_int) {
2511        unsafe {
2512            ffi::rocksdb_options_set_max_background_compactions(self.inner, n);
2513        }
2514    }
2515
2516    /// Sets the maximum number of concurrent background memtable flush jobs, submitted to
2517    /// the HIGH priority thread pool.
2518    ///
2519    /// By default, all background jobs (major compaction and memtable flush) go
2520    /// to the LOW priority pool. If this option is set to a positive number,
2521    /// memtable flush jobs will be submitted to the HIGH priority pool.
2522    /// It is important when the same Env is shared by multiple db instances.
2523    /// Without a separate pool, long running major compaction jobs could
2524    /// potentially block memtable flush jobs of other db instances, leading to
2525    /// unnecessary Put stalls.
2526    ///
2527    /// If you're increasing this, also consider increasing number of threads in
2528    /// HIGH priority thread pool. For more information, see
2529    /// Env::SetBackgroundThreads
2530    ///
2531    /// Default: `1`
2532    ///
2533    /// # Examples
2534    ///
2535    /// ```
2536    /// use rust_rocksdb::Options;
2537    ///
2538    /// let mut opts = Options::default();
2539    /// #[allow(deprecated)]
2540    /// opts.set_max_background_flushes(2);
2541    /// ```
2542    #[deprecated(
2543        since = "0.15.0",
2544        note = "RocksDB automatically decides this based on the value of max_background_jobs"
2545    )]
2546    pub fn set_max_background_flushes(&mut self, n: c_int) {
2547        unsafe {
2548            ffi::rocksdb_options_set_max_background_flushes(self.inner, n);
2549        }
2550    }
2551
2552    /// Disables automatic compactions. Manual compactions can still
2553    /// be issued on this column family
2554    ///
2555    /// Default: `false`
2556    ///
2557    /// Dynamically changeable through SetOptions() API
2558    ///
2559    /// # Examples
2560    ///
2561    /// ```
2562    /// use rust_rocksdb::Options;
2563    ///
2564    /// let mut opts = Options::default();
2565    /// opts.set_disable_auto_compactions(true);
2566    /// ```
2567    pub fn set_disable_auto_compactions(&mut self, disable: bool) {
2568        unsafe {
2569            ffi::rocksdb_options_set_disable_auto_compactions(self.inner, c_int::from(disable));
2570        }
2571    }
2572
2573    /// SetMemtableHugePageSize sets the page size for huge page for
2574    /// arena used by the memtable.
2575    /// If <=0, it won't allocate from huge page but from malloc.
2576    /// Users are responsible to reserve huge pages for it to be allocated. For
2577    /// example:
2578    ///      sysctl -w vm.nr_hugepages=20
2579    /// See linux doc Documentation/vm/hugetlbpage.txt
2580    /// If there isn't enough free huge page available, it will fall back to
2581    /// malloc.
2582    ///
2583    /// Dynamically changeable through SetOptions() API
2584    pub fn set_memtable_huge_page_size(&mut self, size: size_t) {
2585        unsafe {
2586            ffi::rocksdb_options_set_memtable_huge_page_size(self.inner, size);
2587        }
2588    }
2589
2590    /// Sets the maximum number of successive merge operations on a key in the memtable.
2591    ///
2592    /// When a merge operation is added to the memtable and the maximum number of
2593    /// successive merges is reached, the value of the key will be calculated and
2594    /// inserted into the memtable instead of the merge operation. This will
2595    /// ensure that there are never more than max_successive_merges merge
2596    /// operations in the memtable.
2597    ///
2598    /// Default: 0 (disabled)
2599    pub fn set_max_successive_merges(&mut self, num: usize) {
2600        unsafe {
2601            ffi::rocksdb_options_set_max_successive_merges(self.inner, num);
2602        }
2603    }
2604
2605    /// Control locality of bloom filter probes to improve cache miss rate.
2606    /// This option only applies to memtable prefix bloom and plaintable
2607    /// prefix bloom. It essentially limits the max number of cache lines each
2608    /// bloom filter check can touch.
2609    ///
2610    /// This optimization is turned off when set to 0. The number should never
2611    /// be greater than number of probes. This option can boost performance
2612    /// for in-memory workload but should use with care since it can cause
2613    /// higher false positive rate.
2614    ///
2615    /// Default: 0
2616    pub fn set_bloom_locality(&mut self, v: u32) {
2617        unsafe {
2618            ffi::rocksdb_options_set_bloom_locality(self.inner, v);
2619        }
2620    }
2621
2622    /// Enable/disable thread-safe inplace updates.
2623    ///
2624    /// Requires updates if
2625    /// * key exists in current memtable
2626    /// * new sizeof(new_value) <= sizeof(old_value)
2627    /// * old_value for that key is a put i.e. kTypeValue
2628    ///
2629    /// Default: false.
2630    pub fn set_inplace_update_support(&mut self, enabled: bool) {
2631        unsafe {
2632            ffi::rocksdb_options_set_inplace_update_support(self.inner, c_uchar::from(enabled));
2633        }
2634    }
2635
2636    /// Sets the number of locks used for inplace update.
2637    ///
2638    /// Default: 10000 when inplace_update_support = true, otherwise 0.
2639    pub fn set_inplace_update_locks(&mut self, num: usize) {
2640        unsafe {
2641            ffi::rocksdb_options_set_inplace_update_num_locks(self.inner, num);
2642        }
2643    }
2644
2645    /// Different max-size multipliers for different levels.
2646    /// These are multiplied by max_bytes_for_level_multiplier to arrive
2647    /// at the max-size of each level.
2648    ///
2649    /// Default: 1
2650    ///
2651    /// Dynamically changeable through SetOptions() API
2652    pub fn set_max_bytes_for_level_multiplier_additional(&mut self, level_values: &[i32]) {
2653        let count = level_values.len();
2654        unsafe {
2655            ffi::rocksdb_options_set_max_bytes_for_level_multiplier_additional(
2656                self.inner,
2657                level_values.as_ptr().cast_mut(),
2658                count,
2659            );
2660        }
2661    }
2662
2663    /// If true, then DB::Open() will not fetch and check sizes of all sst files.
2664    /// This may significantly speed up startup if there are many sst files,
2665    /// especially when using non-default Env with expensive GetFileSize().
2666    /// We'll still check that all required sst files exist.
2667    /// If paranoid_checks is false, this option is ignored, and sst files are
2668    /// not checked at all.
2669    ///
2670    /// Default: false
2671    #[deprecated(note = "RocksDB >= 10.5: option is ignored: checking done with a thread pool")]
2672    pub fn set_skip_checking_sst_file_sizes_on_db_open(&mut self, value: bool) {
2673        unsafe {
2674            ffi::rocksdb_options_set_skip_checking_sst_file_sizes_on_db_open(
2675                self.inner,
2676                c_uchar::from(value),
2677            );
2678        }
2679    }
2680
2681    /// The total maximum size(bytes) of write buffers to maintain in memory
2682    /// including copies of buffers that have already been flushed. This parameter
2683    /// only affects trimming of flushed buffers and does not affect flushing.
2684    /// This controls the maximum amount of write history that will be available
2685    /// in memory for conflict checking when Transactions are used. The actual
2686    /// size of write history (flushed Memtables) might be higher than this limit
2687    /// if further trimming will reduce write history total size below this
2688    /// limit. For example, if max_write_buffer_size_to_maintain is set to 64MB,
2689    /// and there are three flushed Memtables, with sizes of 32MB, 20MB, 20MB.
2690    /// Because trimming the next Memtable of size 20MB will reduce total memory
2691    /// usage to 52MB which is below the limit, RocksDB will stop trimming.
2692    ///
2693    /// When using an OptimisticTransactionDB:
2694    /// If this value is too low, some transactions may fail at commit time due
2695    /// to not being able to determine whether there were any write conflicts.
2696    ///
2697    /// When using a TransactionDB:
2698    /// If Transaction::SetSnapshot is used, TransactionDB will read either
2699    /// in-memory write buffers or SST files to do write-conflict checking.
2700    /// Increasing this value can reduce the number of reads to SST files
2701    /// done for conflict detection.
2702    ///
2703    /// Setting this value to 0 will cause write buffers to be freed immediately
2704    /// after they are flushed. If this value is set to -1,
2705    /// 'max_write_buffer_number * write_buffer_size' will be used.
2706    ///
2707    /// Default:
2708    /// If using a TransactionDB/OptimisticTransactionDB, the default value will
2709    /// be set to the value of 'max_write_buffer_number * write_buffer_size'
2710    /// if it is not explicitly set by the user.  Otherwise, the default is 0.
2711    pub fn set_max_write_buffer_size_to_maintain(&mut self, size: i64) {
2712        unsafe {
2713            ffi::rocksdb_options_set_max_write_buffer_size_to_maintain(self.inner, size);
2714        }
2715    }
2716
2717    /// By default, a single write thread queue is maintained. The thread gets
2718    /// to the head of the queue becomes write batch group leader and responsible
2719    /// for writing to WAL and memtable for the batch group.
2720    ///
2721    /// If enable_pipelined_write is true, separate write thread queue is
2722    /// maintained for WAL write and memtable write. A write thread first enter WAL
2723    /// writer queue and then memtable writer queue. Pending thread on the WAL
2724    /// writer queue thus only have to wait for previous writers to finish their
2725    /// WAL writing but not the memtable writing. Enabling the feature may improve
2726    /// write throughput and reduce latency of the prepare phase of two-phase
2727    /// commit.
2728    ///
2729    /// Default: false
2730    pub fn set_enable_pipelined_write(&mut self, value: bool) {
2731        unsafe {
2732            ffi::rocksdb_options_set_enable_pipelined_write(self.inner, c_uchar::from(value));
2733        }
2734    }
2735
2736    /// Defines the underlying memtable implementation.
2737    /// See official [wiki](https://github.com/facebook/rocksdb/wiki/MemTable) for more information.
2738    /// Defaults to using a skiplist.
2739    ///
2740    /// # Examples
2741    ///
2742    /// ```
2743    /// use rust_rocksdb::{Options, MemtableFactory};
2744    /// let mut opts = Options::default();
2745    /// let factory = MemtableFactory::HashSkipList {
2746    ///     bucket_count: 1_000_000,
2747    ///     height: 4,
2748    ///     branching_factor: 4,
2749    /// };
2750    ///
2751    /// opts.set_allow_concurrent_memtable_write(false);
2752    /// opts.set_memtable_factory(factory);
2753    /// ```
2754    pub fn set_memtable_factory(&mut self, factory: MemtableFactory) {
2755        match factory {
2756            MemtableFactory::Vector => unsafe {
2757                ffi::rocksdb_options_set_memtable_vector_rep(self.inner);
2758            },
2759            MemtableFactory::HashSkipList {
2760                bucket_count,
2761                height,
2762                branching_factor,
2763            } => unsafe {
2764                ffi::rocksdb_options_set_hash_skip_list_rep(
2765                    self.inner,
2766                    bucket_count,
2767                    height,
2768                    branching_factor,
2769                );
2770            },
2771            MemtableFactory::HashLinkList { bucket_count } => unsafe {
2772                ffi::rocksdb_options_set_hash_link_list_rep(self.inner, bucket_count);
2773            },
2774        }
2775    }
2776
2777    pub fn set_block_based_table_factory(&mut self, factory: &BlockBasedOptions) {
2778        unsafe {
2779            ffi::rocksdb_options_set_block_based_table_factory(self.inner, factory.inner);
2780        }
2781        self.outlive.block_based = Some(factory.outlive.clone());
2782    }
2783
2784    /// Sets the table factory to a CuckooTableFactory (the default table
2785    /// factory is a block-based table factory that provides a default
2786    /// implementation of TableBuilder and TableReader with default
2787    /// BlockBasedTableOptions).
2788    /// See official [wiki](https://github.com/facebook/rocksdb/wiki/CuckooTable-Format) for more information on this table format.
2789    /// # Examples
2790    ///
2791    /// ```
2792    /// use rust_rocksdb::{Options, CuckooTableOptions};
2793    ///
2794    /// let mut opts = Options::default();
2795    /// let mut factory_opts = CuckooTableOptions::default();
2796    /// factory_opts.set_hash_ratio(0.8);
2797    /// factory_opts.set_max_search_depth(20);
2798    /// factory_opts.set_cuckoo_block_size(10);
2799    /// factory_opts.set_identity_as_first_hash(true);
2800    /// factory_opts.set_use_module_hash(false);
2801    ///
2802    /// opts.set_cuckoo_table_factory(&factory_opts);
2803    /// ```
2804    pub fn set_cuckoo_table_factory(&mut self, factory: &CuckooTableOptions) {
2805        unsafe {
2806            ffi::rocksdb_options_set_cuckoo_table_factory(self.inner, factory.inner);
2807        }
2808    }
2809
2810    // This is a factory that provides TableFactory objects.
2811    // Default: a block-based table factory that provides a default
2812    // implementation of TableBuilder and TableReader with default
2813    // BlockBasedTableOptions.
2814    /// Sets the factory as plain table.
2815    /// See official [wiki](https://github.com/facebook/rocksdb/wiki/PlainTable-Format) for more
2816    /// information.
2817    ///
2818    /// # Examples
2819    ///
2820    /// ```
2821    /// use rust_rocksdb::{KeyEncodingType, Options, PlainTableFactoryOptions};
2822    ///
2823    /// let mut opts = Options::default();
2824    /// let factory_opts = PlainTableFactoryOptions {
2825    ///   user_key_length: 0,
2826    ///   bloom_bits_per_key: 20,
2827    ///   hash_table_ratio: 0.75,
2828    ///   index_sparseness: 16,
2829    ///   huge_page_tlb_size: 0,
2830    ///   encoding_type: KeyEncodingType::Plain,
2831    ///   full_scan_mode: false,
2832    ///   store_index_in_file: false,
2833    /// };
2834    ///
2835    /// opts.set_plain_table_factory(&factory_opts);
2836    /// ```
2837    pub fn set_plain_table_factory(&mut self, options: &PlainTableFactoryOptions) {
2838        unsafe {
2839            ffi::rocksdb_options_set_plain_table_factory(
2840                self.inner,
2841                options.user_key_length,
2842                options.bloom_bits_per_key,
2843                options.hash_table_ratio,
2844                options.index_sparseness,
2845                options.huge_page_tlb_size,
2846                options.encoding_type as c_char,
2847                c_uchar::from(options.full_scan_mode),
2848                c_uchar::from(options.store_index_in_file),
2849            );
2850        }
2851    }
2852
2853    /// Sets the start level to use compression.
2854    pub fn set_min_level_to_compress(&mut self, lvl: c_int) {
2855        unsafe {
2856            ffi::rocksdb_options_set_min_level_to_compress(self.inner, lvl);
2857        }
2858    }
2859
2860    /// Measure IO stats in compactions and flushes, if `true`.
2861    ///
2862    /// Default: `false`
2863    ///
2864    /// # Examples
2865    ///
2866    /// ```
2867    /// use rust_rocksdb::Options;
2868    ///
2869    /// let mut opts = Options::default();
2870    /// opts.set_report_bg_io_stats(true);
2871    /// ```
2872    pub fn set_report_bg_io_stats(&mut self, enable: bool) {
2873        unsafe {
2874            ffi::rocksdb_options_set_report_bg_io_stats(self.inner, c_int::from(enable));
2875        }
2876    }
2877
2878    /// Once write-ahead logs exceed this size, we will start forcing the flush of
2879    /// column families whose memtables are backed by the oldest live WAL file
2880    /// (i.e. the ones that are causing all the space amplification).
2881    ///
2882    /// Default: `0`
2883    ///
2884    /// # Examples
2885    ///
2886    /// ```
2887    /// use rust_rocksdb::Options;
2888    ///
2889    /// let mut opts = Options::default();
2890    /// // Set max total wal size to 1G.
2891    /// opts.set_max_total_wal_size(1 << 30);
2892    /// ```
2893    pub fn set_max_total_wal_size(&mut self, size: u64) {
2894        unsafe {
2895            ffi::rocksdb_options_set_max_total_wal_size(self.inner, size);
2896        }
2897    }
2898
2899    /// Recovery mode to control the consistency while replaying WAL.
2900    ///
2901    /// Default: DBRecoveryMode::PointInTime
2902    ///
2903    /// # Examples
2904    ///
2905    /// ```
2906    /// use rust_rocksdb::{Options, DBRecoveryMode};
2907    ///
2908    /// let mut opts = Options::default();
2909    /// opts.set_wal_recovery_mode(DBRecoveryMode::AbsoluteConsistency);
2910    /// ```
2911    pub fn set_wal_recovery_mode(&mut self, mode: DBRecoveryMode) {
2912        unsafe {
2913            ffi::rocksdb_options_set_wal_recovery_mode(self.inner, mode as c_int);
2914        }
2915    }
2916
2917    pub fn enable_statistics(&mut self) {
2918        unsafe {
2919            ffi::rocksdb_options_enable_statistics(self.inner);
2920        }
2921    }
2922
2923    pub fn get_statistics(&self) -> Option<String> {
2924        unsafe {
2925            let value = ffi::rocksdb_options_statistics_get_string(self.inner);
2926            if value.is_null() {
2927                return None;
2928            }
2929
2930            // Must have valid UTF-8 format.
2931            let s = CStr::from_ptr(value).to_str().unwrap().to_owned();
2932            ffi::rocksdb_free(value as *mut c_void);
2933            Some(s)
2934        }
2935    }
2936
2937    /// StatsLevel can be used to reduce statistics overhead by skipping certain
2938    /// types of stats in the stats collection process.
2939    pub fn set_statistics_level(&self, level: StatsLevel) {
2940        unsafe { ffi::rocksdb_options_set_statistics_level(self.inner, level as c_int) }
2941    }
2942
2943    /// Returns the value of cumulative db counters if stat collection is enabled.
2944    pub fn get_ticker_count(&self, ticker: Ticker) -> u64 {
2945        unsafe { ffi::rocksdb_options_statistics_get_ticker_count(self.inner, ticker as u32) }
2946    }
2947
2948    /// Gets Histogram data from collected db stats. Requires stats to be enabled.
2949    pub fn get_histogram_data(&self, histogram: Histogram) -> HistogramData {
2950        unsafe {
2951            let data = HistogramData::default();
2952            ffi::rocksdb_options_statistics_get_histogram_data(
2953                self.inner,
2954                histogram as u32,
2955                data.inner,
2956            );
2957            data
2958        }
2959    }
2960
2961    /// If not zero, dump `rocksdb.stats` to LOG every `stats_dump_period_sec`.
2962    ///
2963    /// Default: `600` (10 mins)
2964    ///
2965    /// # Examples
2966    ///
2967    /// ```
2968    /// use rust_rocksdb::Options;
2969    ///
2970    /// let mut opts = Options::default();
2971    /// opts.set_stats_dump_period_sec(300);
2972    /// ```
2973    pub fn set_stats_dump_period_sec(&mut self, period: c_uint) {
2974        unsafe {
2975            ffi::rocksdb_options_set_stats_dump_period_sec(self.inner, period);
2976        }
2977    }
2978
2979    /// If not zero, dump rocksdb.stats to RocksDB to LOG every `stats_persist_period_sec`.
2980    ///
2981    /// Default: `600` (10 mins)
2982    ///
2983    /// # Examples
2984    ///
2985    /// ```
2986    /// use rust_rocksdb::Options;
2987    ///
2988    /// let mut opts = Options::default();
2989    /// opts.set_stats_persist_period_sec(5);
2990    /// ```
2991    pub fn set_stats_persist_period_sec(&mut self, period: c_uint) {
2992        unsafe {
2993            ffi::rocksdb_options_set_stats_persist_period_sec(self.inner, period);
2994        }
2995    }
2996
2997    /// When set to true, reading SST files will opt out of the filesystem's
2998    /// readahead. Setting this to false may improve sequential iteration
2999    /// performance.
3000    ///
3001    /// Default: `true`
3002    pub fn set_advise_random_on_open(&mut self, advise: bool) {
3003        unsafe {
3004            ffi::rocksdb_options_set_advise_random_on_open(self.inner, c_uchar::from(advise));
3005        }
3006    }
3007
3008    /// Enable/disable adaptive mutex, which spins in the user space before resorting to kernel.
3009    ///
3010    /// This could reduce context switch when the mutex is not
3011    /// heavily contended. However, if the mutex is hot, we could end up
3012    /// wasting spin time.
3013    ///
3014    /// Default: false
3015    pub fn set_use_adaptive_mutex(&mut self, enabled: bool) {
3016        unsafe {
3017            ffi::rocksdb_options_set_use_adaptive_mutex(self.inner, c_uchar::from(enabled));
3018        }
3019    }
3020
3021    /// Sets the number of levels for this database.
3022    pub fn set_num_levels(&mut self, n: c_int) {
3023        unsafe {
3024            ffi::rocksdb_options_set_num_levels(self.inner, n);
3025        }
3026    }
3027
3028    /// When a `prefix_extractor` is defined through `opts.set_prefix_extractor` this
3029    /// creates a prefix bloom filter for each memtable with the size of
3030    /// `write_buffer_size * memtable_prefix_bloom_ratio` (capped at 0.25).
3031    ///
3032    /// Default: `0`
3033    ///
3034    /// # Examples
3035    ///
3036    /// ```
3037    /// use rust_rocksdb::{Options, SliceTransform};
3038    ///
3039    /// let mut opts = Options::default();
3040    /// let transform = SliceTransform::create_fixed_prefix(10);
3041    /// opts.set_prefix_extractor(transform);
3042    /// opts.set_memtable_prefix_bloom_ratio(0.2);
3043    /// ```
3044    pub fn set_memtable_prefix_bloom_ratio(&mut self, ratio: f64) {
3045        unsafe {
3046            ffi::rocksdb_options_set_memtable_prefix_bloom_size_ratio(self.inner, ratio);
3047        }
3048    }
3049
3050    /// Sets the maximum number of bytes in all compacted files.
3051    /// We try to limit number of bytes in one compaction to be lower than this
3052    /// threshold. But it's not guaranteed.
3053    ///
3054    /// Value 0 will be sanitized.
3055    ///
3056    /// Default: target_file_size_base * 25
3057    pub fn set_max_compaction_bytes(&mut self, nbytes: u64) {
3058        unsafe {
3059            ffi::rocksdb_options_set_max_compaction_bytes(self.inner, nbytes);
3060        }
3061    }
3062
3063    /// Specifies the absolute path of the directory the
3064    /// write-ahead log (WAL) should be written to.
3065    ///
3066    /// Default: same directory as the database
3067    ///
3068    /// # Examples
3069    ///
3070    /// ```
3071    /// use rust_rocksdb::Options;
3072    ///
3073    /// let mut opts = Options::default();
3074    /// opts.set_wal_dir("/path/to/dir");
3075    /// ```
3076    pub fn set_wal_dir<P: AsRef<Path>>(&mut self, path: P) {
3077        let p = to_cpath(path).unwrap();
3078        unsafe {
3079            ffi::rocksdb_options_set_wal_dir(self.inner, p.as_ptr());
3080        }
3081    }
3082
3083    /// Sets the WAL ttl in seconds.
3084    ///
3085    /// The following two options affect how archived logs will be deleted.
3086    /// 1. If both set to 0, logs will be deleted asap and will not get into
3087    ///    the archive.
3088    /// 2. If wal_ttl_seconds is 0 and wal_size_limit_mb is not 0,
3089    ///    WAL files will be checked every 10 min and if total size is greater
3090    ///    then wal_size_limit_mb, they will be deleted starting with the
3091    ///    earliest until size_limit is met. All empty files will be deleted.
3092    /// 3. If wal_ttl_seconds is not 0 and wall_size_limit_mb is 0, then
3093    ///    WAL files will be checked every wal_ttl_seconds / 2 and those that
3094    ///    are older than wal_ttl_seconds will be deleted.
3095    /// 4. If both are not 0, WAL files will be checked every 10 min and both
3096    ///    checks will be performed with ttl being first.
3097    ///
3098    /// Default: 0
3099    pub fn set_wal_ttl_seconds(&mut self, secs: u64) {
3100        unsafe {
3101            ffi::rocksdb_options_set_WAL_ttl_seconds(self.inner, secs);
3102        }
3103    }
3104
3105    /// Sets the WAL size limit in MB.
3106    ///
3107    /// If total size of WAL files is greater then wal_size_limit_mb,
3108    /// they will be deleted starting with the earliest until size_limit is met.
3109    ///
3110    /// Default: 0
3111    pub fn set_wal_size_limit_mb(&mut self, size: u64) {
3112        unsafe {
3113            ffi::rocksdb_options_set_WAL_size_limit_MB(self.inner, size);
3114        }
3115    }
3116
3117    /// Sets the number of bytes to preallocate (via fallocate) the manifest files.
3118    ///
3119    /// Default is 4MB, which is reasonable to reduce random IO
3120    /// as well as prevent overallocation for mounts that preallocate
3121    /// large amounts of data (such as xfs's allocsize option).
3122    pub fn set_manifest_preallocation_size(&mut self, size: usize) {
3123        unsafe {
3124            ffi::rocksdb_options_set_manifest_preallocation_size(self.inner, size);
3125        }
3126    }
3127
3128    /// If true, then DB::Open() will not update the statistics used to optimize
3129    /// compaction decision by loading table properties from many files.
3130    /// Turning off this feature will improve DBOpen time especially in disk environment.
3131    ///
3132    /// Default: false
3133    pub fn set_skip_stats_update_on_db_open(&mut self, skip: bool) {
3134        unsafe {
3135            ffi::rocksdb_options_set_skip_stats_update_on_db_open(self.inner, c_uchar::from(skip));
3136        }
3137    }
3138
3139    /// Specify the maximal number of info log files to be kept.
3140    ///
3141    /// Default: 1000
3142    ///
3143    /// # Examples
3144    ///
3145    /// ```
3146    /// use rust_rocksdb::Options;
3147    ///
3148    /// let mut options = Options::default();
3149    /// options.set_keep_log_file_num(100);
3150    /// ```
3151    pub fn set_keep_log_file_num(&mut self, nfiles: usize) {
3152        unsafe {
3153            ffi::rocksdb_options_set_keep_log_file_num(self.inner, nfiles);
3154        }
3155    }
3156
3157    /// Allow the OS to mmap file for writing.
3158    ///
3159    /// Default: false
3160    ///
3161    /// # Examples
3162    ///
3163    /// ```
3164    /// use rust_rocksdb::Options;
3165    ///
3166    /// let mut options = Options::default();
3167    /// options.set_allow_mmap_writes(true);
3168    /// ```
3169    pub fn set_allow_mmap_writes(&mut self, is_enabled: bool) {
3170        unsafe {
3171            ffi::rocksdb_options_set_allow_mmap_writes(self.inner, c_uchar::from(is_enabled));
3172        }
3173    }
3174
3175    /// Allow the OS to mmap file for reading sst tables.
3176    ///
3177    /// Default: false
3178    ///
3179    /// # Examples
3180    ///
3181    /// ```
3182    /// use rust_rocksdb::Options;
3183    ///
3184    /// let mut options = Options::default();
3185    /// options.set_allow_mmap_reads(true);
3186    /// ```
3187    pub fn set_allow_mmap_reads(&mut self, is_enabled: bool) {
3188        unsafe {
3189            ffi::rocksdb_options_set_allow_mmap_reads(self.inner, c_uchar::from(is_enabled));
3190        }
3191    }
3192
3193    /// If enabled, WAL is not flushed automatically after each write. Instead it
3194    /// relies on manual invocation of `DB::flush_wal()` to write the WAL buffer
3195    /// to its file.
3196    ///
3197    /// Default: false
3198    ///
3199    /// # Examples
3200    ///
3201    /// ```
3202    /// use rust_rocksdb::Options;
3203    ///
3204    /// let mut options = Options::default();
3205    /// options.set_manual_wal_flush(true);
3206    /// ```
3207    pub fn set_manual_wal_flush(&mut self, is_enabled: bool) {
3208        unsafe {
3209            ffi::rocksdb_options_set_manual_wal_flush(self.inner, c_uchar::from(is_enabled));
3210        }
3211    }
3212
3213    /// Guarantee that all column families are flushed together atomically.
3214    /// This option applies to both manual flushes (`db.flush()`) and automatic
3215    /// background flushes caused when memtables are filled.
3216    ///
3217    /// Note that this is only useful when the WAL is disabled. When using the
3218    /// WAL, writes are always consistent across column families.
3219    ///
3220    /// Default: false
3221    ///
3222    /// # Examples
3223    ///
3224    /// ```
3225    /// use rust_rocksdb::Options;
3226    ///
3227    /// let mut options = Options::default();
3228    /// options.set_atomic_flush(true);
3229    /// ```
3230    pub fn set_atomic_flush(&mut self, atomic_flush: bool) {
3231        unsafe {
3232            ffi::rocksdb_options_set_atomic_flush(self.inner, c_uchar::from(atomic_flush));
3233        }
3234    }
3235
3236    /// Sets global cache for table-level rows.
3237    ///
3238    /// Default: null (disabled)
3239    /// Not supported in ROCKSDB_LITE mode!
3240    pub fn set_row_cache(&mut self, cache: &Cache) {
3241        unsafe {
3242            ffi::rocksdb_options_set_row_cache(self.inner, cache.0.inner.as_ptr());
3243        }
3244        self.outlive.row_cache = Some(cache.clone());
3245    }
3246
3247    /// Use to control write rate of flush and compaction. Flush has higher
3248    /// priority than compaction.
3249    /// If rate limiter is enabled, bytes_per_sync is set to 1MB by default.
3250    ///
3251    /// Default: disable
3252    ///
3253    /// # Examples
3254    ///
3255    /// ```
3256    /// use rust_rocksdb::Options;
3257    ///
3258    /// let mut options = Options::default();
3259    /// options.set_ratelimiter(1024 * 1024, 100 * 1000, 10);
3260    /// ```
3261    pub fn set_ratelimiter(
3262        &mut self,
3263        rate_bytes_per_sec: i64,
3264        refill_period_us: i64,
3265        fairness: i32,
3266    ) {
3267        unsafe {
3268            let ratelimiter =
3269                ffi::rocksdb_ratelimiter_create(rate_bytes_per_sec, refill_period_us, fairness);
3270            ffi::rocksdb_options_set_ratelimiter(self.inner, ratelimiter);
3271            ffi::rocksdb_ratelimiter_destroy(ratelimiter);
3272        }
3273    }
3274
3275    /// Use to control write rate of flush and compaction. Flush has higher
3276    /// priority than compaction.
3277    /// If rate limiter is enabled, bytes_per_sync is set to 1MB by default.
3278    ///
3279    /// Default: disable
3280    pub fn set_auto_tuned_ratelimiter(
3281        &mut self,
3282        rate_bytes_per_sec: i64,
3283        refill_period_us: i64,
3284        fairness: i32,
3285    ) {
3286        unsafe {
3287            let ratelimiter = ffi::rocksdb_ratelimiter_create_auto_tuned(
3288                rate_bytes_per_sec,
3289                refill_period_us,
3290                fairness,
3291            );
3292            ffi::rocksdb_options_set_ratelimiter(self.inner, ratelimiter);
3293            ffi::rocksdb_ratelimiter_destroy(ratelimiter);
3294        }
3295    }
3296
3297    /// Create a RateLimiter object, which can be shared among RocksDB instances to
3298    /// control write rate of flush and compaction.
3299    ///
3300    /// rate_bytes_per_sec: this is the only parameter you want to set most of the
3301    /// time. It controls the total write rate of compaction and flush in bytes per
3302    /// second. Currently, RocksDB does not enforce rate limit for anything other
3303    /// than flush and compaction, e.g. write to WAL.
3304    ///
3305    /// refill_period_us: this controls how often tokens are refilled. For example,
3306    /// when rate_bytes_per_sec is set to 10MB/s and refill_period_us is set to
3307    /// 100ms, then 1MB is refilled every 100ms internally. Larger value can lead to
3308    /// burstier writes while smaller value introduces more CPU overhead.
3309    /// The default should work for most cases.
3310    ///
3311    /// fairness: RateLimiter accepts high-pri requests and low-pri requests.
3312    /// A low-pri request is usually blocked in favor of hi-pri request. Currently,
3313    /// RocksDB assigns low-pri to request from compaction and high-pri to request
3314    /// from flush. Low-pri requests can get blocked if flush requests come in
3315    /// continuously. This fairness parameter grants low-pri requests permission by
3316    /// 1/fairness chance even though high-pri requests exist to avoid starvation.
3317    /// You should be good by leaving it at default 10.
3318    ///
3319    /// mode: Mode indicates which types of operations count against the limit.
3320    ///
3321    /// auto_tuned: Enables dynamic adjustment of rate limit within the range
3322    ///              `[rate_bytes_per_sec / 20, rate_bytes_per_sec]`, according to
3323    ///              the recent demand for background I/O.
3324    pub fn set_ratelimiter_with_mode(
3325        &mut self,
3326        rate_bytes_per_sec: i64,
3327        refill_period_us: i64,
3328        fairness: i32,
3329        mode: RateLimiterMode,
3330        auto_tuned: bool,
3331    ) {
3332        unsafe {
3333            let ratelimiter = ffi::rocksdb_ratelimiter_create_with_mode(
3334                rate_bytes_per_sec,
3335                refill_period_us,
3336                fairness,
3337                mode as c_int,
3338                auto_tuned,
3339            );
3340            ffi::rocksdb_options_set_ratelimiter(self.inner, ratelimiter);
3341            ffi::rocksdb_ratelimiter_destroy(ratelimiter);
3342        }
3343    }
3344
3345    /// Sets the maximal size of the info log file.
3346    ///
3347    /// If the log file is larger than `max_log_file_size`, a new info log file
3348    /// will be created. If `max_log_file_size` is equal to zero, all logs will
3349    /// be written to one log file.
3350    ///
3351    /// Default: 0
3352    ///
3353    /// # Examples
3354    ///
3355    /// ```
3356    /// use rust_rocksdb::Options;
3357    ///
3358    /// let mut options = Options::default();
3359    /// options.set_max_log_file_size(0);
3360    /// ```
3361    pub fn set_max_log_file_size(&mut self, size: usize) {
3362        unsafe {
3363            ffi::rocksdb_options_set_max_log_file_size(self.inner, size);
3364        }
3365    }
3366
3367    /// Sets the time for the info log file to roll (in seconds).
3368    ///
3369    /// If specified with non-zero value, log file will be rolled
3370    /// if it has been active longer than `log_file_time_to_roll`.
3371    /// Default: 0 (disabled)
3372    pub fn set_log_file_time_to_roll(&mut self, secs: usize) {
3373        unsafe {
3374            ffi::rocksdb_options_set_log_file_time_to_roll(self.inner, secs);
3375        }
3376    }
3377
3378    /// Controls the recycling of log files.
3379    ///
3380    /// If non-zero, previously written log files will be reused for new logs,
3381    /// overwriting the old data. The value indicates how many such files we will
3382    /// keep around at any point in time for later use. This is more efficient
3383    /// because the blocks are already allocated and fdatasync does not need to
3384    /// update the inode after each write.
3385    ///
3386    /// Default: 0
3387    ///
3388    /// # Examples
3389    ///
3390    /// ```
3391    /// use rust_rocksdb::Options;
3392    ///
3393    /// let mut options = Options::default();
3394    /// options.set_recycle_log_file_num(5);
3395    /// ```
3396    pub fn set_recycle_log_file_num(&mut self, num: usize) {
3397        unsafe {
3398            ffi::rocksdb_options_set_recycle_log_file_num(self.inner, num);
3399        }
3400    }
3401
3402    /// Prints logs to stderr for faster debugging
3403    /// See official [wiki](https://github.com/facebook/rocksdb/wiki/Logger) for more information.
3404    pub fn set_stderr_logger(&mut self, log_level: LogLevel, prefix: impl CStrLike) {
3405        let p = prefix.into_c_string().unwrap();
3406
3407        unsafe {
3408            let logger = ffi::rocksdb_logger_create_stderr_logger(log_level as c_int, p.as_ptr());
3409            ffi::rocksdb_options_set_info_log(self.inner, logger);
3410            ffi::rocksdb_logger_destroy(logger);
3411        }
3412    }
3413
3414    /// Invokes `callback` with RocksDB log messages with level >= `log_level`.
3415    ///
3416    /// The callback can be called concurrently by multiple RocksDB threads.
3417    ///
3418    /// # Examples
3419    /// ```
3420    /// use rust_rocksdb::{LogLevel, Options};
3421    ///
3422    /// let mut options = Options::default();
3423    /// options.set_callback_logger(LogLevel::Debug, move |level, msg| println!("{level:?} {msg}"));
3424    /// ```
3425    pub fn set_callback_logger(
3426        &mut self,
3427        log_level: LogLevel,
3428        callback: impl Fn(LogLevel, &str) + 'static + Send + Sync,
3429    ) {
3430        // store the closure in an Arc so it can be shared across multiple Option/DBs
3431        let holder = Arc::new(LogCallback {
3432            callback: Box::new(callback),
3433        });
3434        let holder_ptr = holder.as_ref() as *const LogCallback;
3435        let holder_cvoid = holder_ptr.cast::<c_void>().cast_mut();
3436
3437        unsafe {
3438            let logger = ffi::rocksdb_logger_create_callback_logger(
3439                log_level as c_int,
3440                Some(Self::logger_callback),
3441                holder_cvoid,
3442            );
3443            ffi::rocksdb_options_set_info_log(self.inner, logger);
3444            ffi::rocksdb_logger_destroy(logger);
3445        }
3446
3447        self.outlive.log_callback = Some(holder);
3448    }
3449
3450    extern "C" fn logger_callback(func: *mut c_void, level: u32, msg: *mut c_char, len: usize) {
3451        use std::{mem, process, str};
3452
3453        let level = unsafe { mem::transmute::<u32, LogLevel>(level) };
3454        let slice = unsafe { slice::from_raw_parts_mut(msg.cast::<u8>(), len) };
3455        let msg = unsafe { str::from_utf8_unchecked(slice) };
3456
3457        let holder = unsafe { &mut *func.cast::<LogCallback>() };
3458        let mut callback_in_catch_unwind = AssertUnwindSafe(&mut holder.callback);
3459        if catch_unwind(move || callback_in_catch_unwind(level, msg)).is_err() {
3460            process::abort();
3461        }
3462    }
3463
3464    /// Sets the threshold at which all writes will be slowed down to at least delayed_write_rate if estimated
3465    /// bytes needed to be compaction exceed this threshold.
3466    ///
3467    /// Default: 64GB
3468    pub fn set_soft_pending_compaction_bytes_limit(&mut self, limit: usize) {
3469        unsafe {
3470            ffi::rocksdb_options_set_soft_pending_compaction_bytes_limit(self.inner, limit);
3471        }
3472    }
3473
3474    /// Sets the bytes threshold at which all writes are stopped if estimated bytes needed to be compaction exceed
3475    /// this threshold.
3476    ///
3477    /// Default: 256GB
3478    pub fn set_hard_pending_compaction_bytes_limit(&mut self, limit: usize) {
3479        unsafe {
3480            ffi::rocksdb_options_set_hard_pending_compaction_bytes_limit(self.inner, limit);
3481        }
3482    }
3483
3484    /// Sets the size of one block in arena memory allocation.
3485    ///
3486    /// If <= 0, a proper value is automatically calculated (usually 1/10 of
3487    /// writer_buffer_size).
3488    ///
3489    /// Default: 0
3490    pub fn set_arena_block_size(&mut self, size: usize) {
3491        unsafe {
3492            ffi::rocksdb_options_set_arena_block_size(self.inner, size);
3493        }
3494    }
3495
3496    /// If true, then print malloc stats together with rocksdb.stats when printing to LOG.
3497    ///
3498    /// Default: false
3499    pub fn set_dump_malloc_stats(&mut self, enabled: bool) {
3500        unsafe {
3501            ffi::rocksdb_options_set_dump_malloc_stats(self.inner, c_uchar::from(enabled));
3502        }
3503    }
3504
3505    /// Enable whole key bloom filter in memtable. Note this will only take effect
3506    /// if memtable_prefix_bloom_size_ratio is not 0. Enabling whole key filtering
3507    /// can potentially reduce CPU usage for point-look-ups.
3508    ///
3509    /// Default: false (disable)
3510    ///
3511    /// Dynamically changeable through SetOptions() API
3512    pub fn set_memtable_whole_key_filtering(&mut self, whole_key_filter: bool) {
3513        unsafe {
3514            ffi::rocksdb_options_set_memtable_whole_key_filtering(
3515                self.inner,
3516                c_uchar::from(whole_key_filter),
3517            );
3518        }
3519    }
3520
3521    /// Enable the use of key-value separation.
3522    ///
3523    /// More details can be found here: [Integrated BlobDB](http://rocksdb.org/blog/2021/05/26/integrated-blob-db.html).
3524    ///
3525    /// Default: false (disable)
3526    ///
3527    /// Dynamically changeable through SetOptions() API
3528    pub fn set_enable_blob_files(&mut self, val: bool) {
3529        unsafe {
3530            ffi::rocksdb_options_set_enable_blob_files(self.inner, u8::from(val));
3531        }
3532    }
3533
3534    /// Sets the minimum threshold value at or above which will be written
3535    /// to blob files during flush or compaction.
3536    ///
3537    /// Dynamically changeable through SetOptions() API
3538    pub fn set_min_blob_size(&mut self, val: u64) {
3539        unsafe {
3540            ffi::rocksdb_options_set_min_blob_size(self.inner, val);
3541        }
3542    }
3543
3544    /// Sets the size limit for blob files.
3545    ///
3546    /// Dynamically changeable through SetOptions() API
3547    pub fn set_blob_file_size(&mut self, val: u64) {
3548        unsafe {
3549            ffi::rocksdb_options_set_blob_file_size(self.inner, val);
3550        }
3551    }
3552
3553    /// Sets the blob compression type. All blob files use the same
3554    /// compression type.
3555    ///
3556    /// Dynamically changeable through SetOptions() API
3557    pub fn set_blob_compression_type(&mut self, val: DBCompressionType) {
3558        unsafe {
3559            ffi::rocksdb_options_set_blob_compression_type(self.inner, val as _);
3560        }
3561    }
3562
3563    /// If this is set to true RocksDB will actively relocate valid blobs from the oldest blob files
3564    /// as they are encountered during compaction.
3565    ///
3566    /// Dynamically changeable through SetOptions() API
3567    pub fn set_enable_blob_gc(&mut self, val: bool) {
3568        unsafe {
3569            ffi::rocksdb_options_set_enable_blob_gc(self.inner, u8::from(val));
3570        }
3571    }
3572
3573    /// Sets the threshold that the GC logic uses to determine which blob files should be considered “old.”
3574    ///
3575    /// For example, the default value of 0.25 signals to RocksDB that blobs residing in the
3576    /// oldest 25% of blob files should be relocated by GC. This parameter can be tuned to adjust
3577    /// the trade-off between write amplification and space amplification.
3578    ///
3579    /// Dynamically changeable through SetOptions() API
3580    pub fn set_blob_gc_age_cutoff(&mut self, val: c_double) {
3581        unsafe {
3582            ffi::rocksdb_options_set_blob_gc_age_cutoff(self.inner, val);
3583        }
3584    }
3585
3586    /// Sets the blob GC force threshold.
3587    ///
3588    /// Dynamically changeable through SetOptions() API
3589    pub fn set_blob_gc_force_threshold(&mut self, val: c_double) {
3590        unsafe {
3591            ffi::rocksdb_options_set_blob_gc_force_threshold(self.inner, val);
3592        }
3593    }
3594
3595    /// Sets the blob compaction read ahead size.
3596    ///
3597    /// Dynamically changeable through SetOptions() API
3598    pub fn set_blob_compaction_readahead_size(&mut self, val: u64) {
3599        unsafe {
3600            ffi::rocksdb_options_set_blob_compaction_readahead_size(self.inner, val);
3601        }
3602    }
3603
3604    /// Sets the blob cache.
3605    ///
3606    /// Using a dedicated object for blobs and using the same object for the block and blob caches
3607    /// are both supported. In the latter case, note that blobs are less valuable from a caching
3608    /// perspective than SST blocks, and some cache implementations have configuration options that
3609    /// can be used to prioritize items accordingly (see Cache::Priority and
3610    /// LRUCacheOptions::{high,low}_pri_pool_ratio).
3611    ///
3612    /// Default: disabled
3613    pub fn set_blob_cache(&mut self, cache: &Cache) {
3614        unsafe {
3615            ffi::rocksdb_options_set_blob_cache(self.inner, cache.0.inner.as_ptr());
3616        }
3617        self.outlive.blob_cache = Some(cache.clone());
3618    }
3619
3620    /// Set this option to true during creation of database if you want
3621    /// to be able to ingest behind (call IngestExternalFile() skipping keys
3622    /// that already exist, rather than overwriting matching keys).
3623    /// Setting this option to true has the following effects:
3624    ///
3625    /// 1. Disable some internal optimizations around SST file compression.
3626    /// 2. Reserve the last level for ingested files only.
3627    /// 3. Compaction will not include any file from the last level.
3628    ///
3629    /// Note that only Universal Compaction supports allow_ingest_behind.
3630    /// `num_levels` should be >= 3 if this option is turned on.
3631    ///
3632    /// DEFAULT: false
3633    /// Immutable.
3634    pub fn set_allow_ingest_behind(&mut self, val: bool) {
3635        unsafe {
3636            ffi::rocksdb_options_set_allow_ingest_behind(self.inner, c_uchar::from(val));
3637        }
3638    }
3639
3640    // A factory of a table property collector that marks an SST
3641    // file as need-compaction when it observe at least "D" deletion
3642    // entries in any "N" consecutive entries, or the ratio of tombstone
3643    // entries >= deletion_ratio.
3644    //
3645    // `window_size`: is the sliding window size "N"
3646    // `num_dels_trigger`: is the deletion trigger "D"
3647    // `deletion_ratio`: if <= 0 or > 1, disable triggering compaction based on
3648    // deletion ratio.
3649    pub fn add_compact_on_deletion_collector_factory(
3650        &mut self,
3651        window_size: size_t,
3652        num_dels_trigger: size_t,
3653        deletion_ratio: f64,
3654    ) {
3655        unsafe {
3656            ffi::rocksdb_options_add_compact_on_deletion_collector_factory_del_ratio(
3657                self.inner,
3658                window_size,
3659                num_dels_trigger,
3660                deletion_ratio,
3661            );
3662        }
3663    }
3664
3665    /// Like [`Self::add_compact_on_deletion_collector_factory`], but only triggers
3666    /// compaction if the SST file size is at least `min_file_size` bytes.
3667    pub fn add_compact_on_deletion_collector_factory_min_file_size(
3668        &mut self,
3669        window_size: size_t,
3670        num_dels_trigger: size_t,
3671        deletion_ratio: f64,
3672        min_file_size: u64,
3673    ) {
3674        unsafe {
3675            ffi::rocksdb_options_add_compact_on_deletion_collector_factory_min_file_size(
3676                self.inner,
3677                window_size,
3678                num_dels_trigger,
3679                deletion_ratio,
3680                min_file_size,
3681            );
3682        }
3683    }
3684
3685    /// <https://github.com/facebook/rocksdb/wiki/Write-Buffer-Manager>
3686    /// Write buffer manager helps users control the total memory used by memtables across multiple column families and/or DB instances.
3687    /// Users can enable this control by 2 ways:
3688    ///
3689    /// 1- Limit the total memtable usage across multiple column families and DBs under a threshold.
3690    /// 2- Cost the memtable memory usage to block cache so that memory of RocksDB can be capped by the single limit.
3691    /// The usage of a write buffer manager is similar to rate_limiter and sst_file_manager.
3692    /// Users can create one write buffer manager object and pass it to all the options of column families or DBs whose memtable size they want to be controlled by this object.
3693    pub fn set_write_buffer_manager(&mut self, write_buffer_manager: &WriteBufferManager) {
3694        unsafe {
3695            ffi::rocksdb_options_set_write_buffer_manager(
3696                self.inner,
3697                write_buffer_manager.0.inner.as_ptr(),
3698            );
3699        }
3700        self.outlive.write_buffer_manager = Some(write_buffer_manager.clone());
3701    }
3702
3703    /// Sets an `SstFileManager` for this `Options`.
3704    ///
3705    /// SstFileManager tracks and controls total SST file space usage, enabling
3706    /// applications to cap disk utilization and throttle deletions.
3707    pub fn set_sst_file_manager(&mut self, sst_file_manager: &SstFileManager) {
3708        unsafe {
3709            ffi::rocksdb_options_set_sst_file_manager(
3710                self.inner,
3711                sst_file_manager.0.inner.as_ptr(),
3712            );
3713        }
3714        self.outlive.sst_file_manager = Some(sst_file_manager.clone());
3715    }
3716
3717    /// If true, working thread may avoid doing unnecessary and long-latency
3718    /// operation (such as deleting obsolete files directly or deleting memtable)
3719    /// and will instead schedule a background job to do it.
3720    ///
3721    /// Use it if you're latency-sensitive.
3722    ///
3723    /// Default: false (disabled)
3724    pub fn set_avoid_unnecessary_blocking_io(&mut self, val: bool) {
3725        unsafe {
3726            ffi::rocksdb_options_set_avoid_unnecessary_blocking_io(self.inner, u8::from(val));
3727        }
3728    }
3729
3730    /// Sets the compaction priority.
3731    ///
3732    /// If level compaction_style =
3733    /// kCompactionStyleLevel, for each level, which files are prioritized to be
3734    /// picked to compact.
3735    ///
3736    /// Default: `DBCompactionPri::MinOverlappingRatio`
3737    ///
3738    /// # Examples
3739    ///
3740    /// ```
3741    /// use rust_rocksdb::{Options, DBCompactionPri};
3742    ///
3743    /// let mut opts = Options::default();
3744    /// opts.set_compaction_pri(DBCompactionPri::RoundRobin);
3745    /// ```
3746    pub fn set_compaction_pri(&mut self, pri: DBCompactionPri) {
3747        unsafe {
3748            ffi::rocksdb_options_set_compaction_pri(self.inner, pri as c_int);
3749        }
3750    }
3751
3752    /// If true, the log numbers and sizes of the synced WALs are tracked
3753    /// in MANIFEST. During DB recovery, if a synced WAL is missing
3754    /// from disk, or the WAL's size does not match the recorded size in
3755    /// MANIFEST, an error will be reported and the recovery will be aborted.
3756    ///
3757    /// This is one additional protection against WAL corruption besides the
3758    /// per-WAL-entry checksum.
3759    ///
3760    /// Note that this option does not work with secondary instance.
3761    /// Currently, only syncing closed WALs are tracked. Calling `DB::SyncWAL()`,
3762    /// etc. or writing with `WriteOptions::sync=true` to sync the live WAL is not
3763    /// tracked for performance/efficiency reasons.
3764    ///
3765    /// See: <https://github.com/facebook/rocksdb/wiki/Track-WAL-in-MANIFEST>
3766    ///
3767    /// Default: false (disabled)
3768    pub fn set_track_and_verify_wals_in_manifest(&mut self, val: bool) {
3769        unsafe {
3770            ffi::rocksdb_options_set_track_and_verify_wals_in_manifest(self.inner, u8::from(val));
3771        }
3772    }
3773
3774    /// Returns the value of the `track_and_verify_wals_in_manifest` option.
3775    pub fn get_track_and_verify_wals_in_manifest(&self) -> bool {
3776        let val_u8 =
3777            unsafe { ffi::rocksdb_options_get_track_and_verify_wals_in_manifest(self.inner) };
3778        val_u8 != 0
3779    }
3780
3781    /// The DB unique ID can be saved in the DB manifest (preferred, this option)
3782    /// or an IDENTITY file (historical, deprecated), or both. If this option is
3783    /// set to false (old behavior), then `write_identity_file` must be set to true.
3784    /// The manifest is preferred because
3785    ///
3786    /// 1. The IDENTITY file is not checksummed, so it is not as safe against
3787    ///    corruption.
3788    /// 2. The IDENTITY file may or may not be copied with the DB (e.g. not
3789    ///    copied by BackupEngine), so is not reliable for the provenance of a DB.
3790    ///
3791    /// This option might eventually be obsolete and removed as Identity files
3792    /// are phased out.
3793    ///
3794    /// Default: true (enabled)
3795    pub fn set_write_dbid_to_manifest(&mut self, val: bool) {
3796        unsafe {
3797            ffi::rocksdb_options_set_write_dbid_to_manifest(self.inner, u8::from(val));
3798        }
3799    }
3800
3801    /// Returns the value of the `write_dbid_to_manifest` option.
3802    pub fn get_write_dbid_to_manifest(&self) -> bool {
3803        let val_u8 = unsafe { ffi::rocksdb_options_get_write_dbid_to_manifest(self.inner) };
3804        val_u8 != 0
3805    }
3806}
3807
3808impl Default for Options {
3809    fn default() -> Self {
3810        unsafe {
3811            let opts = ffi::rocksdb_options_create();
3812            assert!(!opts.is_null(), "Could not create RocksDB options");
3813
3814            Self {
3815                inner: opts,
3816                outlive: OptionsMustOutliveDB::default(),
3817            }
3818        }
3819    }
3820}
3821
3822impl FlushOptions {
3823    pub fn new() -> FlushOptions {
3824        FlushOptions::default()
3825    }
3826
3827    /// Waits until the flush is done.
3828    ///
3829    /// Default: true
3830    ///
3831    /// # Examples
3832    ///
3833    /// ```
3834    /// use rust_rocksdb::FlushOptions;
3835    ///
3836    /// let mut options = FlushOptions::default();
3837    /// options.set_wait(false);
3838    /// ```
3839    pub fn set_wait(&mut self, wait: bool) {
3840        unsafe {
3841            ffi::rocksdb_flushoptions_set_wait(self.inner, c_uchar::from(wait));
3842        }
3843    }
3844}
3845
3846impl Default for FlushOptions {
3847    fn default() -> Self {
3848        let flush_opts = unsafe { ffi::rocksdb_flushoptions_create() };
3849        assert!(
3850            !flush_opts.is_null(),
3851            "Could not create RocksDB flush options"
3852        );
3853
3854        Self { inner: flush_opts }
3855    }
3856}
3857
3858impl WriteOptions {
3859    pub fn new() -> WriteOptions {
3860        WriteOptions::default()
3861    }
3862
3863    /// Sets the sync mode. If true, the write will be flushed
3864    /// from the operating system buffer cache before the write is considered complete.
3865    /// If this flag is true, writes will be slower.
3866    ///
3867    /// Default: false
3868    pub fn set_sync(&mut self, sync: bool) {
3869        unsafe {
3870            ffi::rocksdb_writeoptions_set_sync(self.inner, c_uchar::from(sync));
3871        }
3872    }
3873
3874    /// Sets whether WAL should be active or not.
3875    /// If true, writes will not first go to the write ahead log,
3876    /// and the write may got lost after a crash.
3877    ///
3878    /// Default: false
3879    pub fn disable_wal(&mut self, disable: bool) {
3880        unsafe {
3881            ffi::rocksdb_writeoptions_disable_WAL(self.inner, c_int::from(disable));
3882        }
3883    }
3884
3885    /// If true and if user is trying to write to column families that don't exist (they were dropped),
3886    /// ignore the write (don't return an error). If there are multiple writes in a WriteBatch,
3887    /// other writes will succeed.
3888    ///
3889    /// Default: false
3890    pub fn set_ignore_missing_column_families(&mut self, ignore: bool) {
3891        unsafe {
3892            ffi::rocksdb_writeoptions_set_ignore_missing_column_families(
3893                self.inner,
3894                c_uchar::from(ignore),
3895            );
3896        }
3897    }
3898
3899    /// If true and we need to wait or sleep for the write request, fails
3900    /// immediately with Status::Incomplete().
3901    ///
3902    /// Default: false
3903    pub fn set_no_slowdown(&mut self, no_slowdown: bool) {
3904        unsafe {
3905            ffi::rocksdb_writeoptions_set_no_slowdown(self.inner, c_uchar::from(no_slowdown));
3906        }
3907    }
3908
3909    /// If true, this write request is of lower priority if compaction is
3910    /// behind. In this case, no_slowdown = true, the request will be cancelled
3911    /// immediately with Status::Incomplete() returned. Otherwise, it will be
3912    /// slowed down. The slowdown value is determined by RocksDB to guarantee
3913    /// it introduces minimum impacts to high priority writes.
3914    ///
3915    /// Default: false
3916    pub fn set_low_pri(&mut self, v: bool) {
3917        unsafe {
3918            ffi::rocksdb_writeoptions_set_low_pri(self.inner, c_uchar::from(v));
3919        }
3920    }
3921
3922    /// If true, writebatch will maintain the last insert positions of each
3923    /// memtable as hints in concurrent write. It can improve write performance
3924    /// in concurrent writes if keys in one writebatch are sequential. In
3925    /// non-concurrent writes (when concurrent_memtable_writes is false) this
3926    /// option will be ignored.
3927    ///
3928    /// Default: false
3929    pub fn set_memtable_insert_hint_per_batch(&mut self, v: bool) {
3930        unsafe {
3931            ffi::rocksdb_writeoptions_set_memtable_insert_hint_per_batch(
3932                self.inner,
3933                c_uchar::from(v),
3934            );
3935        }
3936    }
3937}
3938
3939impl Default for WriteOptions {
3940    fn default() -> Self {
3941        let write_opts = unsafe { ffi::rocksdb_writeoptions_create() };
3942        assert!(
3943            !write_opts.is_null(),
3944            "Could not create RocksDB write options"
3945        );
3946
3947        Self { inner: write_opts }
3948    }
3949}
3950
3951impl LruCacheOptions {
3952    /// Capacity of the cache, in the same units as the `charge` of each entry.
3953    /// This is typically measured in bytes, but can be a different unit if using
3954    /// kDontChargeCacheMetadata.
3955    pub fn set_capacity(&mut self, cap: usize) {
3956        unsafe {
3957            ffi::rocksdb_lru_cache_options_set_capacity(self.inner, cap);
3958        }
3959    }
3960
3961    /// Cache is sharded into 2^num_shard_bits shards, by hash of key.
3962    /// If < 0, a good default is chosen based on the capacity and the
3963    /// implementation. (Mutex-based implementations are much more reliant
3964    /// on many shards for parallel scalability.)
3965    pub fn set_num_shard_bits(&mut self, val: c_int) {
3966        unsafe {
3967            ffi::rocksdb_lru_cache_options_set_num_shard_bits(self.inner, val);
3968        }
3969    }
3970}
3971
3972impl Default for LruCacheOptions {
3973    fn default() -> Self {
3974        let inner = unsafe { ffi::rocksdb_lru_cache_options_create() };
3975        assert!(
3976            !inner.is_null(),
3977            "Could not create RocksDB LRU cache options"
3978        );
3979
3980        Self { inner }
3981    }
3982}
3983
3984#[derive(Debug, Copy, Clone, PartialEq, Eq)]
3985#[cfg_attr(feature = "serde1", derive(serde::Serialize, serde::Deserialize))]
3986#[repr(i32)]
3987pub enum ReadTier {
3988    /// Reads data in memtable, block cache, OS cache or storage.
3989    All = 0,
3990    /// Reads data in memtable or block cache.
3991    BlockCache,
3992    /// Reads persisted data. When WAL is disabled, this option will skip data in memtable.
3993    Persisted,
3994    /// Reads data in memtable. Used for memtable only iterators.
3995    Memtable,
3996}
3997
3998impl ReadOptions {
3999    // TODO add snapshot setting here
4000    // TODO add snapshot wrapper structs with proper destructors;
4001    // that struct needs an "iterator" impl too.
4002
4003    /// Specify whether the "data block"/"index block"/"filter block"
4004    /// read for this iteration should be cached in memory?
4005    /// Callers may wish to set this field to false for bulk scans.
4006    ///
4007    /// Default: true
4008    pub fn fill_cache(&mut self, v: bool) {
4009        unsafe {
4010            ffi::rocksdb_readoptions_set_fill_cache(self.inner, c_uchar::from(v));
4011        }
4012    }
4013
4014    /// Sets the snapshot which should be used for the read.
4015    /// The snapshot must belong to the DB that is being read and must
4016    /// not have been released.
4017    pub fn set_snapshot<D: DBAccess>(&mut self, snapshot: &SnapshotWithThreadMode<D>) {
4018        unsafe {
4019            ffi::rocksdb_readoptions_set_snapshot(self.inner, snapshot.inner);
4020        }
4021    }
4022
4023    /// Sets the lower bound for an iterator.
4024    pub fn set_iterate_lower_bound<K: Into<Vec<u8>>>(&mut self, key: K) {
4025        self.set_lower_bound_impl(Some(key.into()));
4026    }
4027
4028    /// Sets the upper bound for an iterator.
4029    /// The upper bound itself is not included on the iteration result.
4030    pub fn set_iterate_upper_bound<K: Into<Vec<u8>>>(&mut self, key: K) {
4031        self.set_upper_bound_impl(Some(key.into()));
4032    }
4033
4034    /// Sets lower and upper bounds based on the provided range.  This is
4035    /// similar to setting lower and upper bounds separately except that it also
4036    /// allows either bound to be reset.
4037    ///
4038    /// The argument can be a regular Rust range, e.g. `lower..upper`.  However,
4039    /// since RocksDB upper bound is always excluded (i.e. range can never be
4040    /// fully closed) inclusive ranges (`lower..=upper` and `..=upper`) are not
4041    /// supported.  For example:
4042    ///
4043    /// ```
4044    /// let mut options = rust_rocksdb::ReadOptions::default();
4045    /// options.set_iterate_range("xy".as_bytes().."xz".as_bytes());
4046    /// ```
4047    ///
4048    /// In addition, [`crate::PrefixRange`] can be used to specify a range of
4049    /// keys with a given prefix.  In particular, the above example is
4050    /// equivalent to:
4051    ///
4052    /// ```
4053    /// let mut options = rust_rocksdb::ReadOptions::default();
4054    /// options.set_iterate_range(rust_rocksdb::PrefixRange("xy".as_bytes()));
4055    /// ```
4056    ///
4057    /// Note that setting range using this method is separate to using prefix
4058    /// iterators.  Prefix iterators use prefix extractor configured for
4059    /// a column family.  Setting bounds via [`crate::PrefixRange`] is more akin
4060    /// to using manual prefix.
4061    ///
4062    /// Using this method clears any previously set bounds.  In other words, the
4063    /// bounds can be reset by setting the range to `..` as in:
4064    ///
4065    /// ```
4066    /// let mut options = rust_rocksdb::ReadOptions::default();
4067    /// options.set_iterate_range(..);
4068    /// ```
4069    pub fn set_iterate_range(&mut self, range: impl crate::IterateBounds) {
4070        let (lower, upper) = range.into_bounds();
4071        self.set_lower_bound_impl(lower);
4072        self.set_upper_bound_impl(upper);
4073    }
4074
4075    fn set_lower_bound_impl(&mut self, bound: Option<Vec<u8>>) {
4076        let (ptr, len) = if let Some(ref bound) = bound {
4077            (bound.as_ptr() as *const c_char, bound.len())
4078        } else if self.iterate_lower_bound.is_some() {
4079            (std::ptr::null(), 0)
4080        } else {
4081            return;
4082        };
4083        self.iterate_lower_bound = bound;
4084        unsafe {
4085            ffi::rocksdb_readoptions_set_iterate_lower_bound(self.inner, ptr, len);
4086        }
4087    }
4088
4089    fn set_upper_bound_impl(&mut self, bound: Option<Vec<u8>>) {
4090        let (ptr, len) = if let Some(ref bound) = bound {
4091            (bound.as_ptr() as *const c_char, bound.len())
4092        } else if self.iterate_upper_bound.is_some() {
4093            (std::ptr::null(), 0)
4094        } else {
4095            return;
4096        };
4097        self.iterate_upper_bound = bound;
4098        unsafe {
4099            ffi::rocksdb_readoptions_set_iterate_upper_bound(self.inner, ptr, len);
4100        }
4101    }
4102
4103    /// Specify if this read request should process data that ALREADY
4104    /// resides on a particular cache. If the required data is not
4105    /// found at the specified cache, then Status::Incomplete is returned.
4106    ///
4107    /// Default: ::All
4108    pub fn set_read_tier(&mut self, tier: ReadTier) {
4109        unsafe {
4110            ffi::rocksdb_readoptions_set_read_tier(self.inner, tier as c_int);
4111        }
4112    }
4113
4114    /// Enforce that the iterator only iterates over the same
4115    /// prefix as the seek.
4116    /// This option is effective only for prefix seeks, i.e. prefix_extractor is
4117    /// non-null for the column family and total_order_seek is false.  Unlike
4118    /// iterate_upper_bound, prefix_same_as_start only works within a prefix
4119    /// but in both directions.
4120    ///
4121    /// Default: false
4122    pub fn set_prefix_same_as_start(&mut self, v: bool) {
4123        unsafe {
4124            ffi::rocksdb_readoptions_set_prefix_same_as_start(self.inner, c_uchar::from(v));
4125        }
4126    }
4127
4128    /// Enable a total order seek regardless of index format (e.g. hash index)
4129    /// used in the table. Some table format (e.g. plain table) may not support
4130    /// this option.
4131    ///
4132    /// If true when calling Get(), we also skip prefix bloom when reading from
4133    /// block based table. It provides a way to read existing data after
4134    /// changing implementation of prefix extractor.
4135    pub fn set_total_order_seek(&mut self, v: bool) {
4136        unsafe {
4137            ffi::rocksdb_readoptions_set_total_order_seek(self.inner, c_uchar::from(v));
4138        }
4139    }
4140
4141    /// Sets a threshold for the number of keys that can be skipped
4142    /// before failing an iterator seek as incomplete. The default value of 0 should be used to
4143    /// never fail a request as incomplete, even on skipping too many keys.
4144    ///
4145    /// Default: 0
4146    pub fn set_max_skippable_internal_keys(&mut self, num: u64) {
4147        unsafe {
4148            ffi::rocksdb_readoptions_set_max_skippable_internal_keys(self.inner, num);
4149        }
4150    }
4151
4152    /// If true, when PurgeObsoleteFile is called in CleanupIteratorState, we schedule a background job
4153    /// in the flush job queue and delete obsolete files in background.
4154    ///
4155    /// Default: false
4156    pub fn set_background_purge_on_iterator_cleanup(&mut self, v: bool) {
4157        unsafe {
4158            ffi::rocksdb_readoptions_set_background_purge_on_iterator_cleanup(
4159                self.inner,
4160                c_uchar::from(v),
4161            );
4162        }
4163    }
4164
4165    /// If true, keys deleted using the DeleteRange() API will be visible to
4166    /// readers until they are naturally deleted during compaction.
4167    ///
4168    /// Default: false
4169    #[deprecated(
4170        note = "deprecated in RocksDB 10.2.1: no performance impact if DeleteRange is not used"
4171    )]
4172    pub fn set_ignore_range_deletions(&mut self, v: bool) {
4173        unsafe {
4174            ffi::rocksdb_readoptions_set_ignore_range_deletions(self.inner, c_uchar::from(v));
4175        }
4176    }
4177
4178    /// If true, all data read from underlying storage will be
4179    /// verified against corresponding checksums.
4180    ///
4181    /// Default: true
4182    pub fn set_verify_checksums(&mut self, v: bool) {
4183        unsafe {
4184            ffi::rocksdb_readoptions_set_verify_checksums(self.inner, c_uchar::from(v));
4185        }
4186    }
4187
4188    /// If non-zero, an iterator will create a new table reader which
4189    /// performs reads of the given size. Using a large size (> 2MB) can
4190    /// improve the performance of forward iteration on spinning disks.
4191    /// Default: 0
4192    ///
4193    /// ```
4194    /// use rust_rocksdb::{ReadOptions};
4195    ///
4196    /// let mut opts = ReadOptions::default();
4197    /// opts.set_readahead_size(4_194_304); // 4mb
4198    /// ```
4199    pub fn set_readahead_size(&mut self, v: usize) {
4200        unsafe {
4201            ffi::rocksdb_readoptions_set_readahead_size(self.inner, v as size_t);
4202        }
4203    }
4204
4205    /// If auto_readahead_size is set to true, it will auto tune the readahead_size
4206    /// during scans internally.
4207    /// For this feature to be enabled, iterate_upper_bound must also be specified.
4208    ///
4209    /// NOTE: - Recommended for forward Scans only.
4210    ///       - If there is a backward scans, this option will be
4211    ///         disabled internally and won't be enabled again if the forward scan
4212    ///         is issued again.
4213    ///
4214    /// Default: true
4215    pub fn set_auto_readahead_size(&mut self, v: bool) {
4216        unsafe {
4217            ffi::rocksdb_readoptions_set_auto_readahead_size(self.inner, c_uchar::from(v));
4218        }
4219    }
4220
4221    /// If true, create a tailing iterator. Note that tailing iterators
4222    /// only support moving in the forward direction. Iterating in reverse
4223    /// or seek_to_last are not supported.
4224    pub fn set_tailing(&mut self, v: bool) {
4225        unsafe {
4226            ffi::rocksdb_readoptions_set_tailing(self.inner, c_uchar::from(v));
4227        }
4228    }
4229
4230    /// Specifies the value of "pin_data". If true, it keeps the blocks
4231    /// loaded by the iterator pinned in memory as long as the iterator is not deleted,
4232    /// If used when reading from tables created with
4233    /// BlockBasedTableOptions::use_delta_encoding = false,
4234    /// Iterator's property "rocksdb.iterator.is-key-pinned" is guaranteed to
4235    /// return 1.
4236    ///
4237    /// Default: false
4238    pub fn set_pin_data(&mut self, v: bool) {
4239        unsafe {
4240            ffi::rocksdb_readoptions_set_pin_data(self.inner, c_uchar::from(v));
4241        }
4242    }
4243
4244    /// Asynchronously prefetch some data.
4245    ///
4246    /// Used for sequential reads and internal automatic prefetching.
4247    ///
4248    /// Default: `false`
4249    pub fn set_async_io(&mut self, v: bool) {
4250        unsafe {
4251            ffi::rocksdb_readoptions_set_async_io(self.inner, c_uchar::from(v));
4252        }
4253    }
4254
4255    /// Deadline for completing an API call (Get/MultiGet/Seek/Next for now)
4256    /// in microseconds.
4257    /// It should be set to microseconds since epoch, i.e, gettimeofday or
4258    /// equivalent plus allowed duration in microseconds.
4259    /// This is best effort. The call may exceed the deadline if there is IO
4260    /// involved and the file system doesn't support deadlines, or due to
4261    /// checking for deadline periodically rather than for every key if
4262    /// processing a batch
4263    pub fn set_deadline(&mut self, microseconds: u64) {
4264        unsafe {
4265            ffi::rocksdb_readoptions_set_deadline(self.inner, microseconds);
4266        }
4267    }
4268
4269    /// A timeout in microseconds to be passed to the underlying FileSystem for
4270    /// reads. As opposed to deadline, this determines the timeout for each
4271    /// individual file read request. If a MultiGet/Get/Seek/Next etc call
4272    /// results in multiple reads, each read can last up to io_timeout us.
4273    pub fn set_io_timeout(&mut self, microseconds: u64) {
4274        unsafe {
4275            ffi::rocksdb_readoptions_set_io_timeout(self.inner, microseconds);
4276        }
4277    }
4278
4279    /// Timestamp of operation. Read should return the latest data visible to the
4280    /// specified timestamp. All timestamps of the same database must be of the
4281    /// same length and format. The user is responsible for providing a customized
4282    /// compare function via Comparator to order <key, timestamp> tuples.
4283    /// For iterator, iter_start_ts is the lower bound (older) and timestamp
4284    /// serves as the upper bound. Versions of the same record that fall in
4285    /// the timestamp range will be returned. If iter_start_ts is nullptr,
4286    /// only the most recent version visible to timestamp is returned.
4287    /// The user-specified timestamp feature is still under active development,
4288    /// and the API is subject to change.
4289    pub fn set_timestamp<S: Into<Vec<u8>>>(&mut self, ts: S) {
4290        self.set_timestamp_impl(Some(ts.into()));
4291    }
4292
4293    fn set_timestamp_impl(&mut self, ts: Option<Vec<u8>>) {
4294        let (ptr, len) = if let Some(ref ts) = ts {
4295            (ts.as_ptr() as *const c_char, ts.len())
4296        } else if self.timestamp.is_some() {
4297            // The stored timestamp is a `Some` but we're updating it to a `None`.
4298            // This means to cancel a previously set timestamp.
4299            // To do this, use a null pointer and zero length.
4300            (std::ptr::null(), 0)
4301        } else {
4302            return;
4303        };
4304        self.timestamp = ts;
4305        unsafe {
4306            ffi::rocksdb_readoptions_set_timestamp(self.inner, ptr, len);
4307        }
4308    }
4309
4310    /// See `set_timestamp`
4311    pub fn set_iter_start_ts<S: Into<Vec<u8>>>(&mut self, ts: S) {
4312        self.set_iter_start_ts_impl(Some(ts.into()));
4313    }
4314
4315    fn set_iter_start_ts_impl(&mut self, ts: Option<Vec<u8>>) {
4316        let (ptr, len) = if let Some(ref ts) = ts {
4317            (ts.as_ptr() as *const c_char, ts.len())
4318        } else if self.timestamp.is_some() {
4319            (std::ptr::null(), 0)
4320        } else {
4321            return;
4322        };
4323        self.iter_start_ts = ts;
4324        unsafe {
4325            ffi::rocksdb_readoptions_set_iter_start_ts(self.inner, ptr, len);
4326        }
4327    }
4328}
4329
4330impl Default for ReadOptions {
4331    fn default() -> Self {
4332        unsafe {
4333            Self {
4334                inner: ffi::rocksdb_readoptions_create(),
4335                timestamp: None,
4336                iter_start_ts: None,
4337                iterate_upper_bound: None,
4338                iterate_lower_bound: None,
4339            }
4340        }
4341    }
4342}
4343
4344impl IngestExternalFileOptions {
4345    /// Can be set to true to move the files instead of copying them.
4346    pub fn set_move_files(&mut self, v: bool) {
4347        unsafe {
4348            ffi::rocksdb_ingestexternalfileoptions_set_move_files(self.inner, c_uchar::from(v));
4349        }
4350    }
4351
4352    /// If set to false, an ingested file keys could appear in existing snapshots
4353    /// that where created before the file was ingested.
4354    pub fn set_snapshot_consistency(&mut self, v: bool) {
4355        unsafe {
4356            ffi::rocksdb_ingestexternalfileoptions_set_snapshot_consistency(
4357                self.inner,
4358                c_uchar::from(v),
4359            );
4360        }
4361    }
4362
4363    /// If set to false, IngestExternalFile() will fail if the file key range
4364    /// overlaps with existing keys or tombstones in the DB.
4365    pub fn set_allow_global_seqno(&mut self, v: bool) {
4366        unsafe {
4367            ffi::rocksdb_ingestexternalfileoptions_set_allow_global_seqno(
4368                self.inner,
4369                c_uchar::from(v),
4370            );
4371        }
4372    }
4373
4374    /// If set to false and the file key range overlaps with the memtable key range
4375    /// (memtable flush required), IngestExternalFile will fail.
4376    pub fn set_allow_blocking_flush(&mut self, v: bool) {
4377        unsafe {
4378            ffi::rocksdb_ingestexternalfileoptions_set_allow_blocking_flush(
4379                self.inner,
4380                c_uchar::from(v),
4381            );
4382        }
4383    }
4384
4385    /// Set to true if you would like duplicate keys in the file being ingested
4386    /// to be skipped rather than overwriting existing data under that key.
4387    /// Usecase: back-fill of some historical data in the database without
4388    /// over-writing existing newer version of data.
4389    /// This option could only be used if the DB has been running
4390    /// with allow_ingest_behind=true since the dawn of time.
4391    /// All files will be ingested at the bottommost level with seqno=0.
4392    pub fn set_ingest_behind(&mut self, v: bool) {
4393        unsafe {
4394            ffi::rocksdb_ingestexternalfileoptions_set_ingest_behind(self.inner, c_uchar::from(v));
4395        }
4396    }
4397}
4398
4399impl Default for IngestExternalFileOptions {
4400    fn default() -> Self {
4401        unsafe {
4402            Self {
4403                inner: ffi::rocksdb_ingestexternalfileoptions_create(),
4404            }
4405        }
4406    }
4407}
4408
4409/// Used by BlockBasedOptions::set_index_type.
4410pub enum BlockBasedIndexType {
4411    /// A space efficient index block that is optimized for
4412    /// binary-search-based index.
4413    BinarySearch,
4414
4415    /// The hash index, if enabled, will perform a hash lookup if
4416    /// a prefix extractor has been provided through Options::set_prefix_extractor.
4417    HashSearch,
4418
4419    /// A two-level index implementation. Both levels are binary search indexes.
4420    TwoLevelIndexSearch,
4421}
4422
4423/// Used by BlockBasedOptions::set_data_block_index_type.
4424#[repr(C)]
4425pub enum DataBlockIndexType {
4426    /// Use binary search when performing point lookup for keys in data blocks.
4427    /// This is the default.
4428    BinarySearch = 0,
4429
4430    /// Appends a compact hash table to the end of the data block for efficient indexing. Backwards
4431    /// compatible with databases created without this feature. Once turned on, existing data will
4432    /// be gradually converted to the hash index format.
4433    BinaryAndHash = 1,
4434}
4435
4436/// Defines the underlying memtable implementation.
4437/// See official [wiki](https://github.com/facebook/rocksdb/wiki/MemTable) for more information.
4438pub enum MemtableFactory {
4439    Vector,
4440    HashSkipList {
4441        bucket_count: usize,
4442        height: i32,
4443        branching_factor: i32,
4444    },
4445    HashLinkList {
4446        bucket_count: usize,
4447    },
4448}
4449
4450/// Used by BlockBasedOptions::set_checksum_type.
4451pub enum ChecksumType {
4452    NoChecksum = 0,
4453    CRC32c = 1,
4454    XXHash = 2,
4455    XXHash64 = 3,
4456    XXH3 = 4, // Supported since RocksDB 6.27
4457}
4458
4459/// Used in [`PlainTableFactoryOptions`].
4460#[derive(Debug, Copy, Clone, PartialEq, Eq, Default)]
4461pub enum KeyEncodingType {
4462    /// Always write full keys.
4463    #[default]
4464    Plain = 0,
4465    /// Find opportunities to write the same prefix for multiple rows.
4466    Prefix = 1,
4467}
4468
4469/// Used with DBOptions::set_plain_table_factory.
4470/// See official [wiki](https://github.com/facebook/rocksdb/wiki/PlainTable-Format) for more
4471/// information.
4472///
4473/// Defaults:
4474///  user_key_length: 0 (variable length)
4475///  bloom_bits_per_key: 10
4476///  hash_table_ratio: 0.75
4477///  index_sparseness: 16
4478///  huge_page_tlb_size: 0
4479///  encoding_type: KeyEncodingType::Plain
4480///  full_scan_mode: false
4481///  store_index_in_file: false
4482pub struct PlainTableFactoryOptions {
4483    pub user_key_length: u32,
4484    pub bloom_bits_per_key: i32,
4485    pub hash_table_ratio: f64,
4486    pub index_sparseness: usize,
4487    pub huge_page_tlb_size: usize,
4488    pub encoding_type: KeyEncodingType,
4489    pub full_scan_mode: bool,
4490    pub store_index_in_file: bool,
4491}
4492
4493#[derive(Debug, Copy, Clone, PartialEq, Eq)]
4494#[cfg_attr(feature = "serde1", derive(serde::Serialize, serde::Deserialize))]
4495pub enum DBCompressionType {
4496    None = ffi::rocksdb_no_compression as isize,
4497    Snappy = ffi::rocksdb_snappy_compression as isize,
4498    Zlib = ffi::rocksdb_zlib_compression as isize,
4499    Bz2 = ffi::rocksdb_bz2_compression as isize,
4500    Lz4 = ffi::rocksdb_lz4_compression as isize,
4501    Lz4hc = ffi::rocksdb_lz4hc_compression as isize,
4502    Zstd = ffi::rocksdb_zstd_compression as isize,
4503}
4504
4505#[derive(Debug, Copy, Clone, PartialEq, Eq)]
4506#[cfg_attr(feature = "serde1", derive(serde::Serialize, serde::Deserialize))]
4507pub enum DBCompactionStyle {
4508    Level = ffi::rocksdb_level_compaction as isize,
4509    Universal = ffi::rocksdb_universal_compaction as isize,
4510    Fifo = ffi::rocksdb_fifo_compaction as isize,
4511}
4512
4513#[derive(Debug, Copy, Clone, PartialEq, Eq)]
4514#[cfg_attr(feature = "serde1", derive(serde::Serialize, serde::Deserialize))]
4515pub enum DBRecoveryMode {
4516    TolerateCorruptedTailRecords = ffi::rocksdb_tolerate_corrupted_tail_records_recovery as isize,
4517    AbsoluteConsistency = ffi::rocksdb_absolute_consistency_recovery as isize,
4518    PointInTime = ffi::rocksdb_point_in_time_recovery as isize,
4519    SkipAnyCorruptedRecord = ffi::rocksdb_skip_any_corrupted_records_recovery as isize,
4520}
4521
4522#[derive(Debug, Copy, Clone, PartialEq, Eq)]
4523#[repr(i32)]
4524pub enum RateLimiterMode {
4525    KReadsOnly = 0,
4526    KWritesOnly = 1,
4527    KAllIo = 2,
4528}
4529
4530#[derive(Debug, Copy, Clone, PartialEq, Eq)]
4531#[cfg_attr(feature = "serde1", derive(serde::Serialize, serde::Deserialize))]
4532pub enum DBCompactionPri {
4533    ByCompensatedSize = ffi::rocksdb_k_by_compensated_size_compaction_pri as isize,
4534    OldestLargestSeqFirst = ffi::rocksdb_k_oldest_largest_seq_first_compaction_pri as isize,
4535    OldestSmallestSeqFirst = ffi::rocksdb_k_oldest_smallest_seq_first_compaction_pri as isize,
4536    MinOverlappingRatio = ffi::rocksdb_k_min_overlapping_ratio_compaction_pri as isize,
4537    RoundRobin = ffi::rocksdb_k_round_robin_compaction_pri as isize,
4538}
4539
4540#[derive(Debug, Copy, Clone, PartialEq, Eq)]
4541#[cfg_attr(feature = "serde1", derive(serde::Serialize, serde::Deserialize))]
4542pub enum BlockBasedPinningTier {
4543    Fallback = ffi::rocksdb_block_based_k_fallback_pinning_tier as isize,
4544    None = ffi::rocksdb_block_based_k_none_pinning_tier as isize,
4545    FlushAndSimilar = ffi::rocksdb_block_based_k_flush_and_similar_pinning_tier as isize,
4546    All = ffi::rocksdb_block_based_k_all_pinning_tier as isize,
4547}
4548
4549pub struct FifoCompactOptions {
4550    pub(crate) inner: *mut ffi::rocksdb_fifo_compaction_options_t,
4551}
4552
4553impl Default for FifoCompactOptions {
4554    fn default() -> Self {
4555        let opts = unsafe { ffi::rocksdb_fifo_compaction_options_create() };
4556        assert!(
4557            !opts.is_null(),
4558            "Could not create RocksDB Fifo Compaction Options"
4559        );
4560
4561        Self { inner: opts }
4562    }
4563}
4564
4565impl Drop for FifoCompactOptions {
4566    fn drop(&mut self) {
4567        unsafe {
4568            ffi::rocksdb_fifo_compaction_options_destroy(self.inner);
4569        }
4570    }
4571}
4572
4573impl FifoCompactOptions {
4574    /// Sets the max table file size.
4575    ///
4576    /// Once the total sum of table files reaches this, we will delete the oldest
4577    /// table file
4578    ///
4579    /// Default: 1GB
4580    pub fn set_max_table_files_size(&mut self, nbytes: u64) {
4581        unsafe {
4582            ffi::rocksdb_fifo_compaction_options_set_max_table_files_size(self.inner, nbytes);
4583        }
4584    }
4585}
4586
4587#[derive(Debug, Copy, Clone, PartialEq, Eq)]
4588#[cfg_attr(feature = "serde1", derive(serde::Serialize, serde::Deserialize))]
4589pub enum UniversalCompactionStopStyle {
4590    Similar = ffi::rocksdb_similar_size_compaction_stop_style as isize,
4591    Total = ffi::rocksdb_total_size_compaction_stop_style as isize,
4592}
4593
4594pub struct UniversalCompactOptions {
4595    pub(crate) inner: *mut ffi::rocksdb_universal_compaction_options_t,
4596}
4597
4598impl Default for UniversalCompactOptions {
4599    fn default() -> Self {
4600        let opts = unsafe { ffi::rocksdb_universal_compaction_options_create() };
4601        assert!(
4602            !opts.is_null(),
4603            "Could not create RocksDB Universal Compaction Options"
4604        );
4605
4606        Self { inner: opts }
4607    }
4608}
4609
4610impl Drop for UniversalCompactOptions {
4611    fn drop(&mut self) {
4612        unsafe {
4613            ffi::rocksdb_universal_compaction_options_destroy(self.inner);
4614        }
4615    }
4616}
4617
4618impl UniversalCompactOptions {
4619    /// Sets the percentage flexibility while comparing file size.
4620    /// If the candidate file(s) size is 1% smaller than the next file's size,
4621    /// then include next file into this candidate set.
4622    ///
4623    /// Default: 1
4624    pub fn set_size_ratio(&mut self, ratio: c_int) {
4625        unsafe {
4626            ffi::rocksdb_universal_compaction_options_set_size_ratio(self.inner, ratio);
4627        }
4628    }
4629
4630    /// Sets the minimum number of files in a single compaction run.
4631    ///
4632    /// Default: 2
4633    pub fn set_min_merge_width(&mut self, num: c_int) {
4634        unsafe {
4635            ffi::rocksdb_universal_compaction_options_set_min_merge_width(self.inner, num);
4636        }
4637    }
4638
4639    /// Sets the maximum number of files in a single compaction run.
4640    ///
4641    /// Default: UINT_MAX
4642    pub fn set_max_merge_width(&mut self, num: c_int) {
4643        unsafe {
4644            ffi::rocksdb_universal_compaction_options_set_max_merge_width(self.inner, num);
4645        }
4646    }
4647
4648    /// sets the size amplification.
4649    ///
4650    /// It is defined as the amount (in percentage) of
4651    /// additional storage needed to store a single byte of data in the database.
4652    /// For example, a size amplification of 2% means that a database that
4653    /// contains 100 bytes of user-data may occupy upto 102 bytes of
4654    /// physical storage. By this definition, a fully compacted database has
4655    /// a size amplification of 0%. Rocksdb uses the following heuristic
4656    /// to calculate size amplification: it assumes that all files excluding
4657    /// the earliest file contribute to the size amplification.
4658    ///
4659    /// Default: 200, which means that a 100 byte database could require upto 300 bytes of storage.
4660    pub fn set_max_size_amplification_percent(&mut self, v: c_int) {
4661        unsafe {
4662            ffi::rocksdb_universal_compaction_options_set_max_size_amplification_percent(
4663                self.inner, v,
4664            );
4665        }
4666    }
4667
4668    /// Sets the percentage of compression size.
4669    ///
4670    /// If this option is set to be -1, all the output files
4671    /// will follow compression type specified.
4672    ///
4673    /// If this option is not negative, we will try to make sure compressed
4674    /// size is just above this value. In normal cases, at least this percentage
4675    /// of data will be compressed.
4676    /// When we are compacting to a new file, here is the criteria whether
4677    /// it needs to be compressed: assuming here are the list of files sorted
4678    /// by generation time:
4679    ///    A1...An B1...Bm C1...Ct
4680    /// where A1 is the newest and Ct is the oldest, and we are going to compact
4681    /// B1...Bm, we calculate the total size of all the files as total_size, as
4682    /// well as  the total size of C1...Ct as total_C, the compaction output file
4683    /// will be compressed iff
4684    ///   total_C / total_size < this percentage
4685    ///
4686    /// Default: -1
4687    pub fn set_compression_size_percent(&mut self, v: c_int) {
4688        unsafe {
4689            ffi::rocksdb_universal_compaction_options_set_compression_size_percent(self.inner, v);
4690        }
4691    }
4692
4693    /// Sets the algorithm used to stop picking files into a single compaction run.
4694    ///
4695    /// Default: ::Total
4696    pub fn set_stop_style(&mut self, style: UniversalCompactionStopStyle) {
4697        unsafe {
4698            ffi::rocksdb_universal_compaction_options_set_stop_style(self.inner, style as c_int);
4699        }
4700    }
4701}
4702
4703#[derive(Debug, Copy, Clone, PartialEq, Eq)]
4704#[cfg_attr(feature = "serde1", derive(serde::Serialize, serde::Deserialize))]
4705#[repr(u8)]
4706pub enum BottommostLevelCompaction {
4707    /// Skip bottommost level compaction
4708    Skip = 0,
4709    /// Only compact bottommost level if there is a compaction filter
4710    /// This is the default option
4711    IfHaveCompactionFilter,
4712    /// Always compact bottommost level
4713    Force,
4714    /// Always compact bottommost level but in bottommost level avoid
4715    /// double-compacting files created in the same compaction
4716    ForceOptimized,
4717}
4718
4719pub struct CompactOptions {
4720    pub(crate) inner: *mut ffi::rocksdb_compactoptions_t,
4721    full_history_ts_low: Option<Vec<u8>>,
4722}
4723
4724impl Default for CompactOptions {
4725    fn default() -> Self {
4726        let opts = unsafe { ffi::rocksdb_compactoptions_create() };
4727        assert!(!opts.is_null(), "Could not create RocksDB Compact Options");
4728
4729        Self {
4730            inner: opts,
4731            full_history_ts_low: None,
4732        }
4733    }
4734}
4735
4736impl Drop for CompactOptions {
4737    fn drop(&mut self) {
4738        unsafe {
4739            ffi::rocksdb_compactoptions_destroy(self.inner);
4740        }
4741    }
4742}
4743
4744impl CompactOptions {
4745    /// If more than one thread calls manual compaction,
4746    /// only one will actually schedule it while the other threads will simply wait
4747    /// for the scheduled manual compaction to complete. If exclusive_manual_compaction
4748    /// is set to true, the call will disable scheduling of automatic compaction jobs
4749    /// and wait for existing automatic compaction jobs to finish.
4750    pub fn set_exclusive_manual_compaction(&mut self, v: bool) {
4751        unsafe {
4752            ffi::rocksdb_compactoptions_set_exclusive_manual_compaction(
4753                self.inner,
4754                c_uchar::from(v),
4755            );
4756        }
4757    }
4758
4759    /// Sets bottommost level compaction.
4760    pub fn set_bottommost_level_compaction(&mut self, lvl: BottommostLevelCompaction) {
4761        unsafe {
4762            ffi::rocksdb_compactoptions_set_bottommost_level_compaction(self.inner, lvl as c_uchar);
4763        }
4764    }
4765
4766    /// If true, compacted files will be moved to the minimum level capable
4767    /// of holding the data or given level (specified non-negative target_level).
4768    pub fn set_change_level(&mut self, v: bool) {
4769        unsafe {
4770            ffi::rocksdb_compactoptions_set_change_level(self.inner, c_uchar::from(v));
4771        }
4772    }
4773
4774    /// If change_level is true and target_level have non-negative value, compacted
4775    /// files will be moved to target_level.
4776    pub fn set_target_level(&mut self, lvl: c_int) {
4777        unsafe {
4778            ffi::rocksdb_compactoptions_set_target_level(self.inner, lvl);
4779        }
4780    }
4781
4782    /// Set user-defined timestamp low bound, the data with older timestamp than
4783    /// low bound maybe GCed by compaction. Default: nullptr
4784    pub fn set_full_history_ts_low<S: Into<Vec<u8>>>(&mut self, ts: S) {
4785        self.set_full_history_ts_low_impl(Some(ts.into()));
4786    }
4787
4788    fn set_full_history_ts_low_impl(&mut self, ts: Option<Vec<u8>>) {
4789        let (ptr, len) = if let Some(ref ts) = ts {
4790            (ts.as_ptr() as *mut c_char, ts.len())
4791        } else if self.full_history_ts_low.is_some() {
4792            (std::ptr::null::<Vec<u8>>() as *mut c_char, 0)
4793        } else {
4794            return;
4795        };
4796        self.full_history_ts_low = ts;
4797        unsafe {
4798            ffi::rocksdb_compactoptions_set_full_history_ts_low(self.inner, ptr, len);
4799        }
4800    }
4801}
4802
4803pub struct WaitForCompactOptions {
4804    pub(crate) inner: *mut ffi::rocksdb_wait_for_compact_options_t,
4805}
4806
4807impl Default for WaitForCompactOptions {
4808    fn default() -> Self {
4809        let opts = unsafe { ffi::rocksdb_wait_for_compact_options_create() };
4810        assert!(
4811            !opts.is_null(),
4812            "Could not create RocksDB Wait For Compact Options"
4813        );
4814
4815        Self { inner: opts }
4816    }
4817}
4818
4819impl Drop for WaitForCompactOptions {
4820    fn drop(&mut self) {
4821        unsafe {
4822            ffi::rocksdb_wait_for_compact_options_destroy(self.inner);
4823        }
4824    }
4825}
4826
4827impl WaitForCompactOptions {
4828    /// If true, abort waiting if background jobs are paused. If false,
4829    /// ContinueBackgroundWork() must be called to resume the background jobs.
4830    /// Otherwise, jobs that were queued, but not scheduled yet may never finish
4831    /// and WaitForCompact() may wait indefinitely (if timeout is set, it will
4832    /// abort after the timeout).
4833    ///
4834    /// Default: false
4835    pub fn set_abort_on_pause(&mut self, v: bool) {
4836        unsafe {
4837            ffi::rocksdb_wait_for_compact_options_set_abort_on_pause(self.inner, c_uchar::from(v));
4838        }
4839    }
4840
4841    /// If true, flush all column families before starting to wait.
4842    ///
4843    /// Default: false
4844    pub fn set_flush(&mut self, v: bool) {
4845        unsafe {
4846            ffi::rocksdb_wait_for_compact_options_set_flush(self.inner, c_uchar::from(v));
4847        }
4848    }
4849
4850    /// Timeout in microseconds for waiting for compaction to complete.
4851    /// when timeout == 0, WaitForCompact() will wait as long as there's background
4852    /// work to finish.
4853    ///
4854    /// Default: 0
4855    pub fn set_timeout(&mut self, microseconds: u64) {
4856        unsafe {
4857            ffi::rocksdb_wait_for_compact_options_set_timeout(self.inner, microseconds);
4858        }
4859    }
4860}
4861
4862/// Represents a path where sst files can be put into
4863pub struct DBPath {
4864    pub(crate) inner: *mut ffi::rocksdb_dbpath_t,
4865}
4866
4867impl DBPath {
4868    /// Create a new path
4869    pub fn new<P: AsRef<Path>>(path: P, target_size: u64) -> Result<Self, Error> {
4870        let p = to_cpath(path.as_ref()).unwrap();
4871        let dbpath = unsafe { ffi::rocksdb_dbpath_create(p.as_ptr(), target_size) };
4872        if dbpath.is_null() {
4873            Err(Error::new(format!(
4874                "Could not create path for storing sst files at location: {}",
4875                path.as_ref().display()
4876            )))
4877        } else {
4878            Ok(DBPath { inner: dbpath })
4879        }
4880    }
4881}
4882
4883impl Drop for DBPath {
4884    fn drop(&mut self) {
4885        unsafe {
4886            ffi::rocksdb_dbpath_destroy(self.inner);
4887        }
4888    }
4889}
4890
4891/// Options for importing column families. See
4892/// [DB::create_column_family_with_import](crate::DB::create_column_family_with_import).
4893pub struct ImportColumnFamilyOptions {
4894    pub(crate) inner: *mut ffi::rocksdb_import_column_family_options_t,
4895}
4896
4897impl ImportColumnFamilyOptions {
4898    pub fn new() -> Self {
4899        let inner = unsafe { ffi::rocksdb_import_column_family_options_create() };
4900        ImportColumnFamilyOptions { inner }
4901    }
4902
4903    /// Determines whether to move the provided set of files on import. The default
4904    /// behavior is to copy the external files on import. Setting `move_files` to `true`
4905    /// will move the files instead of copying them. See
4906    /// [DB::create_column_family_with_import](crate::DB::create_column_family_with_import)
4907    /// for more information.
4908    pub fn set_move_files(&mut self, move_files: bool) {
4909        unsafe {
4910            ffi::rocksdb_import_column_family_options_set_move_files(
4911                self.inner,
4912                c_uchar::from(move_files),
4913            );
4914        }
4915    }
4916}
4917
4918impl Default for ImportColumnFamilyOptions {
4919    fn default() -> Self {
4920        Self::new()
4921    }
4922}
4923
4924impl Drop for ImportColumnFamilyOptions {
4925    fn drop(&mut self) {
4926        unsafe { ffi::rocksdb_import_column_family_options_destroy(self.inner) }
4927    }
4928}
4929
4930#[cfg(test)]
4931mod tests {
4932    use crate::cache::Cache;
4933    use crate::db_options::WriteBufferManager;
4934    use crate::{MemtableFactory, Options};
4935
4936    #[test]
4937    fn test_enable_statistics() {
4938        let mut opts = Options::default();
4939        opts.enable_statistics();
4940        opts.set_stats_dump_period_sec(60);
4941        assert!(opts.get_statistics().is_some());
4942
4943        let opts = Options::default();
4944        assert!(opts.get_statistics().is_none());
4945    }
4946
4947    #[test]
4948    fn test_set_memtable_factory() {
4949        let mut opts = Options::default();
4950        opts.set_memtable_factory(MemtableFactory::Vector);
4951        opts.set_memtable_factory(MemtableFactory::HashLinkList { bucket_count: 100 });
4952        opts.set_memtable_factory(MemtableFactory::HashSkipList {
4953            bucket_count: 100,
4954            height: 4,
4955            branching_factor: 4,
4956        });
4957    }
4958
4959    #[test]
4960    fn test_use_fsync() {
4961        let mut opts = Options::default();
4962        assert!(!opts.get_use_fsync());
4963        opts.set_use_fsync(true);
4964        assert!(opts.get_use_fsync());
4965    }
4966
4967    #[test]
4968    fn test_set_stats_persist_period_sec() {
4969        let mut opts = Options::default();
4970        opts.enable_statistics();
4971        opts.set_stats_persist_period_sec(5);
4972        assert!(opts.get_statistics().is_some());
4973
4974        let opts = Options::default();
4975        assert!(opts.get_statistics().is_none());
4976    }
4977
4978    #[test]
4979    fn test_set_write_buffer_manager() {
4980        let mut opts = Options::default();
4981        let lrucache = Cache::new_lru_cache(100);
4982        let write_buffer_manager =
4983            WriteBufferManager::new_write_buffer_manager_with_cache(100, false, lrucache);
4984        assert_eq!(write_buffer_manager.get_buffer_size(), 100);
4985        assert_eq!(write_buffer_manager.get_usage(), 0);
4986        assert!(write_buffer_manager.enabled());
4987
4988        opts.set_write_buffer_manager(&write_buffer_manager);
4989        drop(opts);
4990
4991        // WriteBufferManager outlives options
4992        assert!(write_buffer_manager.enabled());
4993    }
4994}