Skip to main content

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::panic::{AssertUnwindSafe, catch_unwind};
16use std::path::Path;
17use std::ptr::{NonNull, null_mut};
18use std::slice;
19use std::sync::Arc;
20
21use libc::{self, c_char, c_double, c_int, c_uchar, c_uint, c_void, size_t};
22
23use crate::cache::{Cache, MemoryAllocator};
24use crate::column_family::ColumnFamilyTtl;
25use crate::compaction_service::{CompactionService, new_compaction_service};
26use crate::event_listener::{EventListener, new_event_listener};
27use crate::ffi_util::from_cstr_and_free;
28use crate::file_checksum::FileChecksumGenFactory;
29use crate::metadata::FileType;
30use crate::sst_file_manager::SstFileManager;
31use crate::sst_partitioner::SstPartitionerFactory;
32use crate::statistics::{Histogram, HistogramData, StatsLevel};
33use crate::table_properties::TableProperties;
34use crate::wal_filter::{OwnedWalFilter, WalFilter, new_wal_filter};
35use crate::write_buffer_manager::WriteBufferManager;
36use crate::{
37    ColumnFamilyDescriptor, Error, SnapshotWithThreadMode,
38    compaction_filter::{self, CompactionFilterCallback, CompactionFilterFn},
39    compaction_filter_factory::{self, CompactionFilterFactory},
40    comparator::{
41        Comparator, ComparatorCallback, ComparatorWithTsCallback, CompareFn, CompareTsFn,
42        CompareWithoutTsFn,
43    },
44    db::DBAccess,
45    env::{Env, IoPriority},
46    ffi,
47    ffi_util::{CStrLike, to_cpath},
48    merge_operator::{
49        self, MergeFn, MergeOperatorCallback, full_merge_callback, partial_merge_callback,
50    },
51    slice_transform::SliceTransform,
52    statistics::Ticker,
53};
54
55// must be Send and Sync because it will be called by RocksDB from different threads
56type LogCallbackFn = dyn Fn(LogLevel, &str) + 'static + Send + Sync;
57
58/// Type for log callbacks used by [`Options::set_info_logger`]. Use Box to pass a thin pointer to
59/// the C callback.
60type LoggerCallback = Box<dyn Fn(LogLevel, &str) + Sync + Send>;
61
62// Holds a log callback to ensure it outlives any Options and DBs that use it.
63struct LogCallback {
64    callback: Box<LogCallbackFn>,
65}
66
67/// Options that must outlive the DB, and may be shared between DBs. This is cloned and stored
68/// with every DB that is created from the options.
69#[derive(Default)]
70pub(crate) struct OptionsMustOutliveDB {
71    env: Option<Env>,
72    row_cache: Option<Cache>,
73    blob_cache: Option<Cache>,
74    block_based: Option<BlockBasedOptionsMustOutliveDB>,
75    write_buffer_manager: Option<WriteBufferManager>,
76    sst_file_manager: Option<SstFileManager>,
77    log_callback: Option<Arc<LogCallback>>,
78    comparator: Option<Arc<Comparator>>,
79    compaction_filter: Option<Arc<OwnedCompactionFilter>>,
80    logger_callback: Option<Arc<LoggerCallback>>,
81    wal_filter: Option<Arc<OwnedWalFilter>>,
82}
83
84impl OptionsMustOutliveDB {
85    pub(crate) fn clone(&self) -> Self {
86        Self {
87            env: self.env.clone(),
88            row_cache: self.row_cache.clone(),
89            blob_cache: self.blob_cache.clone(),
90            block_based: self
91                .block_based
92                .as_ref()
93                .map(BlockBasedOptionsMustOutliveDB::clone),
94            write_buffer_manager: self.write_buffer_manager.clone(),
95            sst_file_manager: self.sst_file_manager.clone(),
96            log_callback: self.log_callback.clone(),
97            comparator: self.comparator.clone(),
98            compaction_filter: self.compaction_filter.clone(),
99            logger_callback: self.logger_callback.clone(),
100            wal_filter: self.wal_filter.clone(),
101        }
102    }
103}
104
105/// Stores a `rocksdb_compactionfilter_t` and destroys it when dropped.
106///
107/// Needed because the C API only ever borrows the filter it is handed, both from
108/// [`Options`] and from `CompactionServiceOptionsOverride`, so whoever set it has to
109/// outlive it and free it.
110pub(crate) struct OwnedCompactionFilter {
111    inner: NonNull<ffi::rocksdb_compactionfilter_t>,
112}
113
114impl OwnedCompactionFilter {
115    pub(crate) fn new(inner: NonNull<ffi::rocksdb_compactionfilter_t>) -> Self {
116        Self { inner }
117    }
118}
119
120impl Drop for OwnedCompactionFilter {
121    fn drop(&mut self) {
122        unsafe {
123            ffi::rocksdb_compactionfilter_destroy(self.inner.as_ptr());
124        }
125    }
126}
127
128#[derive(Default)]
129struct BlockBasedOptionsMustOutliveDB {
130    block_cache: Option<Cache>,
131}
132
133impl BlockBasedOptionsMustOutliveDB {
134    fn clone(&self) -> Self {
135        Self {
136            block_cache: self.block_cache.clone(),
137        }
138    }
139}
140
141/// Database-wide options around performance and behavior.
142///
143/// Please read the official tuning [guide](https://github.com/facebook/rocksdb/wiki/RocksDB-Tuning-Guide)
144/// and most importantly, measure performance under realistic workloads with realistic hardware.
145///
146/// # Examples
147///
148/// ```
149/// use rust_rocksdb::{Options, DB};
150/// use rust_rocksdb::DBCompactionStyle;
151///
152/// fn badly_tuned_for_somebody_elses_disk() -> DB {
153///    let path = "path/for/rocksdb/storageX";
154///    let mut opts = Options::default();
155///    opts.create_if_missing(true);
156///    opts.set_max_open_files(10000);
157///    opts.set_use_fsync(false);
158///    opts.set_bytes_per_sync(8388608);
159///    opts.optimize_for_point_lookup(1024);
160///    opts.set_table_cache_num_shard_bits(6);
161///    opts.set_max_write_buffer_number(32);
162///    opts.set_write_buffer_size(536870912);
163///    opts.set_target_file_size_base(1073741824);
164///    opts.set_min_write_buffer_number_to_merge(4);
165///    opts.set_level_zero_stop_writes_trigger(2000);
166///    opts.set_level_zero_slowdown_writes_trigger(0);
167///    opts.set_compaction_style(DBCompactionStyle::Universal);
168///    opts.set_disable_auto_compactions(true);
169///
170///    DB::open(&opts, path).unwrap()
171/// }
172/// ```
173pub struct Options {
174    pub(crate) inner: *mut ffi::rocksdb_options_t,
175    pub(crate) outlive: OptionsMustOutliveDB,
176}
177
178/// Optionally disable WAL or sync for this write.
179///
180/// # Examples
181///
182/// Making an unsafe write of a batch:
183///
184/// ```
185/// use rust_rocksdb::{DB, Options, WriteBatch, WriteOptions};
186///
187/// let tempdir = tempfile::Builder::new()
188///     .prefix("_path_for_rocksdb_storageY1")
189///     .tempdir()
190///     .expect("Failed to create temporary path for the _path_for_rocksdb_storageY1");
191/// let path = tempdir.path();
192/// {
193///     let db = DB::open_default(path).unwrap();
194///     let mut batch = WriteBatch::default();
195///     batch.put(b"my key", b"my value");
196///     batch.put(b"key2", b"value2");
197///     batch.put(b"key3", b"value3");
198///
199///     let mut write_options = WriteOptions::default();
200///     write_options.set_sync(false);
201///     write_options.disable_wal(true);
202///
203///     db.write_opt(&batch, &write_options);
204/// }
205/// let _ = DB::destroy(&Options::default(), path);
206/// ```
207pub struct WriteOptions {
208    pub(crate) inner: *mut ffi::rocksdb_writeoptions_t,
209}
210
211pub struct LruCacheOptions {
212    pub(crate) inner: *mut ffi::rocksdb_lru_cache_options_t,
213}
214
215/// Optionally wait for the memtable flush to be performed.
216///
217/// # Examples
218///
219/// Manually flushing the memtable:
220///
221/// ```
222/// use rust_rocksdb::{DB, Options, FlushOptions};
223///
224/// let tempdir = tempfile::Builder::new()
225///     .prefix("_path_for_rocksdb_storageY2")
226///     .tempdir()
227///     .expect("Failed to create temporary path for the _path_for_rocksdb_storageY2");
228/// let path = tempdir.path();
229/// {
230///     let db = DB::open_default(path).unwrap();
231///
232///     let mut flush_options = FlushOptions::default();
233///     flush_options.set_wait(true);
234///
235///     db.flush_opt(&flush_options);
236/// }
237/// let _ = DB::destroy(&Options::default(), path);
238/// ```
239pub struct FlushOptions {
240    pub(crate) inner: *mut ffi::rocksdb_flushoptions_t,
241}
242
243/// Options for the `_with_options` variants of
244/// [`DB::get_approximate_sizes`](crate::DB::get_approximate_sizes).
245///
246/// At least one of [`set_include_memtables`](Self::set_include_memtables),
247/// [`set_include_files`](Self::set_include_files) and
248/// [`set_include_blob_files`](Self::set_include_blob_files) has to be on, or
249/// there is nothing left to measure.
250pub struct SizeApproximationOptions {
251    pub(crate) inner: *mut ffi::rocksdb_size_approximation_options_t,
252}
253
254/// Which kinds of data [`DB::get_approximate_sizes_cf_with_flags`] counts.
255///
256/// This is the older flag-based form of [`SizeApproximationOptions`], kept
257/// because it is the only variant RocksDB exposes for a single column family
258/// without allocating an options object. It cannot express an error margin.
259///
260/// [`DB::get_approximate_sizes_cf_with_flags`]: crate::DB::get_approximate_sizes_cf_with_flags
261#[derive(Debug, Copy, Clone, PartialEq, Eq, Default)]
262pub struct SizeApproximationFlags(u8);
263
264impl SizeApproximationFlags {
265    /// Count nothing, which makes every returned size zero.
266    pub const NONE: Self = Self(ffi::rocksdb_size_approximation_flags_none as u8);
267    /// Count data still in the memtables.
268    pub const INCLUDE_MEMTABLE: Self =
269        Self(ffi::rocksdb_size_approximation_flags_include_memtable as u8);
270    /// Count data in SST files.
271    pub const INCLUDE_FILES: Self = Self(ffi::rocksdb_size_approximation_flags_include_files as u8);
272    /// Count a prorated share of the blob files, as described on
273    /// [`SizeApproximationOptions::set_include_blob_files`].
274    pub const INCLUDE_BLOB_FILES: Self =
275        Self(ffi::rocksdb_size_approximation_flags_include_blob_files as u8);
276
277    pub(crate) fn bits(self) -> u8 {
278        self.0
279    }
280}
281
282impl std::ops::BitOr for SizeApproximationFlags {
283    type Output = Self;
284
285    fn bitor(self, rhs: Self) -> Self {
286        Self(self.0 | rhs.0)
287    }
288}
289
290impl std::ops::BitOrAssign for SizeApproximationFlags {
291    fn bitor_assign(&mut self, rhs: Self) {
292        self.0 |= rhs.0;
293    }
294}
295
296/// Options for [`DB::flush_wal_with_options`](crate::DB::flush_wal_with_options).
297///
298/// Flushing the WAL moves buffered writes from RocksDB's own memory into the
299/// operating system, which is what makes them survive a process crash. It takes
300/// an `fsync` on top of that, requested with [`set_sync`](Self::set_sync), to
301/// survive losing the machine.
302pub struct FlushWalOptions {
303    pub(crate) inner: *mut ffi::rocksdb_flushwaloptions_t,
304}
305
306/// For configuring block-based file storage.
307pub struct BlockBasedOptions {
308    pub(crate) inner: *mut ffi::rocksdb_block_based_table_options_t,
309    outlive: BlockBasedOptionsMustOutliveDB,
310}
311
312pub struct ReadOptions {
313    pub(crate) inner: *mut ffi::rocksdb_readoptions_t,
314    // The `ReadOptions` owns a copy of the timestamp and iteration bounds.
315    // This is necessary to ensure the pointers we pass over the FFI live as
316    // long as the `ReadOptions`. This way, when performing the read operation,
317    // the pointers are guaranteed to be valid.
318    timestamp: Option<Vec<u8>>,
319    iter_start_ts: Option<Vec<u8>>,
320    iterate_upper_bound: Option<Vec<u8>>,
321    iterate_lower_bound: Option<Vec<u8>>,
322}
323
324/// Configuration of cuckoo-based storage.
325pub struct CuckooTableOptions {
326    pub(crate) inner: *mut ffi::rocksdb_cuckoo_table_options_t,
327}
328
329/// For configuring external files ingestion.
330///
331/// # Examples
332///
333/// Move files instead of copying them:
334///
335/// ```
336/// use rust_rocksdb::{DB, IngestExternalFileOptions, SstFileWriter, Options};
337///
338/// let writer_opts = Options::default();
339/// let mut writer = SstFileWriter::create(&writer_opts);
340/// let tempdir = tempfile::Builder::new()
341///     .tempdir()
342///     .expect("Failed to create temporary folder for the _path_for_sst_file");
343/// let path1 = tempdir.path().join("_path_for_sst_file");
344/// writer.open(path1.clone()).unwrap();
345/// writer.put(b"k1", b"v1").unwrap();
346/// writer.finish().unwrap();
347///
348/// let tempdir2 = tempfile::Builder::new()
349///     .prefix("_path_for_rocksdb_storageY3")
350///     .tempdir()
351///     .expect("Failed to create temporary path for the _path_for_rocksdb_storageY3");
352/// let path2 = tempdir2.path();
353/// {
354///   let db = DB::open_default(&path2).unwrap();
355///   let mut ingest_opts = IngestExternalFileOptions::default();
356///   ingest_opts.set_move_files(true);
357///   db.ingest_external_file_opts(&ingest_opts, vec![path1]).unwrap();
358/// }
359/// let _ = DB::destroy(&Options::default(), path2);
360/// ```
361pub struct IngestExternalFileOptions {
362    pub(crate) inner: *mut ffi::rocksdb_ingestexternalfileoptions_t,
363}
364
365// Safety note: auto-implementing Send on most db-related types is prevented by the inner FFI
366// pointer. In most cases, however, this pointer is Send-safe because it is never aliased and
367// rocksdb internally does not rely on thread-local information for its user-exposed types.
368unsafe impl Send for Options {}
369unsafe impl Send for WriteOptions {}
370unsafe impl Send for LruCacheOptions {}
371unsafe impl Send for FlushOptions {}
372unsafe impl Send for BlockBasedOptions {}
373unsafe impl Send for CuckooTableOptions {}
374unsafe impl Send for ReadOptions {}
375unsafe impl Send for IngestExternalFileOptions {}
376unsafe impl Send for CompactOptions {}
377unsafe impl Send for ImportColumnFamilyOptions {}
378unsafe impl Send for OwnedCompactionFilter {}
379
380// Sync is similarly safe for many types because they do not expose interior mutability, and their
381// use within the rocksdb library is generally behind a const reference
382unsafe impl Sync for Options {}
383unsafe impl Sync for WriteOptions {}
384unsafe impl Sync for LruCacheOptions {}
385unsafe impl Sync for FlushOptions {}
386unsafe impl Sync for BlockBasedOptions {}
387unsafe impl Sync for CuckooTableOptions {}
388unsafe impl Sync for ReadOptions {}
389unsafe impl Sync for IngestExternalFileOptions {}
390unsafe impl Sync for CompactOptions {}
391unsafe impl Sync for ImportColumnFamilyOptions {}
392unsafe impl Sync for OwnedCompactionFilter {}
393
394impl Drop for Options {
395    fn drop(&mut self) {
396        unsafe {
397            ffi::rocksdb_options_destroy(self.inner);
398        }
399    }
400}
401
402impl Clone for Options {
403    fn clone(&self) -> Self {
404        let inner = unsafe { ffi::rocksdb_options_create_copy(self.inner) };
405        assert!(!inner.is_null(), "Could not copy RocksDB options");
406
407        Self {
408            inner,
409            outlive: self.outlive.clone(),
410        }
411    }
412}
413
414impl Drop for BlockBasedOptions {
415    fn drop(&mut self) {
416        unsafe {
417            ffi::rocksdb_block_based_options_destroy(self.inner);
418        }
419    }
420}
421
422impl Drop for CuckooTableOptions {
423    fn drop(&mut self) {
424        unsafe {
425            ffi::rocksdb_cuckoo_options_destroy(self.inner);
426        }
427    }
428}
429
430impl Drop for FlushOptions {
431    fn drop(&mut self) {
432        unsafe {
433            ffi::rocksdb_flushoptions_destroy(self.inner);
434        }
435    }
436}
437
438impl Drop for FlushWalOptions {
439    fn drop(&mut self) {
440        unsafe {
441            ffi::rocksdb_flushwaloptions_destroy(self.inner);
442        }
443    }
444}
445
446impl Drop for SizeApproximationOptions {
447    fn drop(&mut self) {
448        unsafe {
449            ffi::rocksdb_size_approximation_options_destroy(self.inner);
450        }
451    }
452}
453
454impl Drop for WriteOptions {
455    fn drop(&mut self) {
456        unsafe {
457            ffi::rocksdb_writeoptions_destroy(self.inner);
458        }
459    }
460}
461
462impl Drop for LruCacheOptions {
463    fn drop(&mut self) {
464        unsafe {
465            ffi::rocksdb_lru_cache_options_destroy(self.inner);
466        }
467    }
468}
469
470impl Drop for ReadOptions {
471    fn drop(&mut self) {
472        unsafe {
473            ffi::rocksdb_readoptions_destroy(self.inner);
474        }
475    }
476}
477
478impl Drop for IngestExternalFileOptions {
479    fn drop(&mut self) {
480        unsafe {
481            ffi::rocksdb_ingestexternalfileoptions_destroy(self.inner);
482        }
483    }
484}
485
486/// Copies a `const char*` plus length pair that the C API borrows out of an options object.
487///
488/// Every getter that uses this returns `opt->rep.<field>.data()` or a factory's `Name()` (see
489/// `db/c.cc`), so the bytes belong to RocksDB and must be copied rather than freed. Invalid
490/// UTF-8 is replaced, matching [`from_cstr_and_free`].
491///
492/// # Safety
493///
494/// `ptr` must either be null or point to `len` readable bytes that stay valid for the call.
495unsafe fn borrowed_string(ptr: *const c_char, len: usize) -> String {
496    if ptr.is_null() || len == 0 {
497        return String::new();
498    }
499    let bytes = unsafe { slice::from_raw_parts(ptr.cast::<u8>(), len) };
500    String::from_utf8_lossy(bytes).into_owned()
501}
502
503/// Maps a [`FileType`] onto the `rocksdb::FileType` value the checksum handoff set accepts.
504///
505/// `checksum_handoff_file_types` is a `SmallEnumSet<FileType, kBlobFile>`, so RocksDB asserts
506/// on any value above `kBlobFile`. [`FileType::CompactionProgressFile`] and
507/// [`FileType::Unknown`] sit above it and have no representation in the set.
508fn checksum_handoff_file_type_raw(file_type: FileType) -> Option<c_int> {
509    // Variants below `kBlobFile` are their own `rocksdb::FileType` value, so
510    // the discriminant is the raw int; the enum is the only place the mapping
511    // is written down.
512    match file_type {
513        FileType::CompactionProgressFile | FileType::Unknown => None,
514        representable => Some(representable as c_int),
515    }
516}
517
518impl BlockBasedOptions {
519    /// Approximate size of user data packed per block. Note that the
520    /// block size specified here corresponds to uncompressed data. The
521    /// actual size of the unit read from disk may be smaller if
522    /// compression is enabled. This parameter can be changed dynamically.
523    pub fn set_block_size(&mut self, size: usize) {
524        unsafe {
525            ffi::rocksdb_block_based_options_set_block_size(self.inner, size);
526        }
527    }
528
529    /// Block size for partitioned metadata. Currently applied to indexes when
530    /// kTwoLevelIndexSearch is used and to filters when partition_filters is used.
531    /// Note: Since in the current implementation the filters and index partitions
532    /// are aligned, an index/filter block is created when either index or filter
533    /// block size reaches the specified limit.
534    ///
535    /// Note: this limit is currently applied to only index blocks; a filter
536    /// partition is cut right after an index block is cut.
537    pub fn set_metadata_block_size(&mut self, size: usize) {
538        unsafe {
539            ffi::rocksdb_block_based_options_set_metadata_block_size(self.inner, size as u64);
540        }
541    }
542
543    /// Note: currently this option requires kTwoLevelIndexSearch to be set as
544    /// well.
545    ///
546    /// Use partitioned full filters for each SST file. This option is
547    /// incompatible with block-based filters.
548    pub fn set_partition_filters(&mut self, size: bool) {
549        unsafe {
550            ffi::rocksdb_block_based_options_set_partition_filters(self.inner, c_uchar::from(size));
551        }
552    }
553
554    /// Sets global cache for blocks (user data is stored in a set of blocks, and
555    /// a block is the unit of reading from disk).
556    ///
557    /// If set, use the specified cache for blocks.
558    /// By default, rocksdb will automatically create and use an 8MB internal cache.
559    pub fn set_block_cache(&mut self, cache: &Cache) {
560        unsafe {
561            ffi::rocksdb_block_based_options_set_block_cache(self.inner, cache.0.inner.as_ptr());
562        }
563        self.outlive.block_cache = Some(cache.clone());
564    }
565
566    /// Disable block cache
567    pub fn disable_cache(&mut self) {
568        unsafe {
569            ffi::rocksdb_block_based_options_set_no_block_cache(self.inner, c_uchar::from(true));
570        }
571    }
572
573    /// Sets a [Bloom filter](https://github.com/facebook/rocksdb/wiki/RocksDB-Bloom-Filter)
574    /// policy to reduce disk reads.
575    ///
576    /// # Examples
577    ///
578    /// ```
579    /// use rust_rocksdb::BlockBasedOptions;
580    ///
581    /// let mut opts = BlockBasedOptions::default();
582    /// opts.set_bloom_filter(10.0, true);
583    /// ```
584    pub fn set_bloom_filter(&mut self, bits_per_key: c_double, block_based: bool) {
585        unsafe {
586            let bloom = if block_based {
587                ffi::rocksdb_filterpolicy_create_bloom(bits_per_key as _)
588            } else {
589                ffi::rocksdb_filterpolicy_create_bloom_full(bits_per_key as _)
590            };
591
592            ffi::rocksdb_block_based_options_set_filter_policy(self.inner, bloom);
593        }
594    }
595
596    /// Sets a [Ribbon filter](http://rocksdb.org/blog/2021/12/29/ribbon-filter.html)
597    /// policy to reduce disk reads.
598    ///
599    /// Ribbon filters use less memory in exchange for slightly more CPU usage
600    /// compared to an equivalent bloom filter.
601    ///
602    /// # Examples
603    ///
604    /// ```
605    /// use rust_rocksdb::BlockBasedOptions;
606    ///
607    /// let mut opts = BlockBasedOptions::default();
608    /// opts.set_ribbon_filter(10.0);
609    /// ```
610    pub fn set_ribbon_filter(&mut self, bloom_equivalent_bits_per_key: c_double) {
611        unsafe {
612            let ribbon = ffi::rocksdb_filterpolicy_create_ribbon(bloom_equivalent_bits_per_key);
613            ffi::rocksdb_block_based_options_set_filter_policy(self.inner, ribbon);
614        }
615    }
616
617    /// Sets a hybrid [Ribbon filter](http://rocksdb.org/blog/2021/12/29/ribbon-filter.html)
618    /// policy to reduce disk reads.
619    ///
620    /// Uses Bloom filters before the given level, and Ribbon filters for all
621    /// other levels. This combines the memory savings from Ribbon filters
622    /// with the lower CPU usage of Bloom filters.
623    ///
624    /// # Examples
625    ///
626    /// ```
627    /// use rust_rocksdb::BlockBasedOptions;
628    ///
629    /// let mut opts = BlockBasedOptions::default();
630    /// opts.set_hybrid_ribbon_filter(10.0, 2);
631    /// ```
632    pub fn set_hybrid_ribbon_filter(
633        &mut self,
634        bloom_equivalent_bits_per_key: c_double,
635        bloom_before_level: c_int,
636    ) {
637        unsafe {
638            let ribbon = ffi::rocksdb_filterpolicy_create_ribbon_hybrid(
639                bloom_equivalent_bits_per_key,
640                bloom_before_level,
641            );
642            ffi::rocksdb_block_based_options_set_filter_policy(self.inner, ribbon);
643        }
644    }
645
646    /// Whether to put index/filter blocks in the block cache. When false,
647    /// each "table reader" object will pre-load index/filter blocks during
648    /// table initialization. Index and filter partition blocks always use
649    /// block cache regardless of this option.
650    ///
651    /// Default: false
652    pub fn set_cache_index_and_filter_blocks(&mut self, v: bool) {
653        unsafe {
654            ffi::rocksdb_block_based_options_set_cache_index_and_filter_blocks(
655                self.inner,
656                c_uchar::from(v),
657            );
658        }
659    }
660
661    /// If `cache_index_and_filter_blocks` is enabled, cache index and filter
662    /// blocks with high priority. Depending on the block cache implementation,
663    /// index, filter, and other metadata blocks may be less likely to be
664    /// evicted than data blocks when this is set to true.
665    ///
666    /// Default: true.
667    pub fn set_cache_index_and_filter_blocks_with_high_priority(&mut self, v: bool) {
668        unsafe {
669            ffi::rocksdb_block_based_options_set_cache_index_and_filter_blocks_with_high_priority(
670                self.inner,
671                c_uchar::from(v),
672            );
673        }
674    }
675
676    /// Defines the index type to be used for SS-table lookups.
677    ///
678    /// # Examples
679    ///
680    /// ```
681    /// use rust_rocksdb::{BlockBasedOptions, BlockBasedIndexType, Options};
682    ///
683    /// let mut opts = Options::default();
684    /// let mut block_opts = BlockBasedOptions::default();
685    /// block_opts.set_index_type(BlockBasedIndexType::HashSearch);
686    /// ```
687    pub fn set_index_type(&mut self, index_type: BlockBasedIndexType) {
688        let index = index_type as i32;
689        unsafe {
690            ffi::rocksdb_block_based_options_set_index_type(self.inner, index);
691        }
692    }
693
694    /// Selects the search algorithm used inside each index block at lookup
695    /// time.
696    ///
697    /// Use [`IndexBlockSearchType::Interpolation`] when keys in index blocks
698    /// are known to be uniformly distributed and the byte-wise comparator is
699    /// in use, or [`IndexBlockSearchType::Auto`] to let RocksDB choose per
700    /// block. `Auto` requires the corresponding write-path threshold to be
701    /// set via [`Self::set_uniform_cv_threshold`]; otherwise it falls back to
702    /// binary search.
703    ///
704    /// Default: `IndexBlockSearchType::Binary`
705    ///
706    /// # Examples
707    ///
708    /// ```
709    /// use rust_rocksdb::{BlockBasedOptions, IndexBlockSearchType};
710    ///
711    /// let mut block_opts = BlockBasedOptions::default();
712    /// block_opts.set_index_block_search_type(IndexBlockSearchType::Auto);
713    /// block_opts.set_uniform_cv_threshold(0.2);
714    /// ```
715    pub fn set_index_block_search_type(&mut self, search_type: IndexBlockSearchType) {
716        unsafe {
717            ffi::rocksdb_block_based_options_set_index_block_search_type(
718                self.inner,
719                search_type as c_int,
720            );
721        }
722    }
723
724    /// Coefficient of variation (CV) threshold used on the write path to
725    /// decide whether an index block's keys are "uniform" enough to benefit
726    /// from interpolation search at read time. When the CV of key gaps within
727    /// an index block is below this threshold, the per-block "is_uniform"
728    /// footer bit is set, which
729    /// [`IndexBlockSearchType::Auto`](Self::set_index_block_search_type)
730    /// consults at lookup time.
731    ///
732    /// Any negative value disables the feature; the magnitude is ignored.
733    /// With the default disabled value, [`IndexBlockSearchType::Auto`]
734    /// degenerates to binary search at read time because the per-block
735    /// "is_uniform" bit is never written. The recommended enabled range is
736    /// `0.0..=1.0`; a typical value is `0.2`.
737    ///
738    /// Note: currently only index blocks honour this; the value has no effect
739    /// on data blocks today.
740    ///
741    /// Default: `-1.0` (disabled)
742    ///
743    /// # Examples
744    ///
745    /// ```
746    /// use rust_rocksdb::BlockBasedOptions;
747    ///
748    /// let mut block_opts = BlockBasedOptions::default();
749    /// block_opts.set_uniform_cv_threshold(0.2);
750    /// ```
751    pub fn set_uniform_cv_threshold(&mut self, threshold: f64) {
752        unsafe {
753            ffi::rocksdb_block_based_options_set_uniform_cv_threshold(self.inner, threshold);
754        }
755    }
756
757    /// If cache_index_and_filter_blocks is true and the below is true, then
758    /// filter and index blocks are stored in the cache, but a reference is
759    /// held in the "table reader" object so the blocks are pinned and only
760    /// evicted from cache when the table reader is freed.
761    ///
762    /// Default: false.
763    pub fn set_pin_l0_filter_and_index_blocks_in_cache(&mut self, v: bool) {
764        unsafe {
765            ffi::rocksdb_block_based_options_set_pin_l0_filter_and_index_blocks_in_cache(
766                self.inner,
767                c_uchar::from(v),
768            );
769        }
770    }
771
772    /// If cache_index_and_filter_blocks is true and the below is true, then
773    /// the top-level index of partitioned filter and index blocks are stored in
774    /// the cache, but a reference is held in the "table reader" object so the
775    /// blocks are pinned and only evicted from cache when the table reader is
776    /// freed. This is not limited to l0 in LSM tree.
777    ///
778    /// Default: true.
779    pub fn set_pin_top_level_index_and_filter(&mut self, v: bool) {
780        unsafe {
781            ffi::rocksdb_block_based_options_set_pin_top_level_index_and_filter(
782                self.inner,
783                c_uchar::from(v),
784            );
785        }
786    }
787
788    /// Format version, reserved for backward compatibility.
789    ///
790    /// See full [list](https://github.com/facebook/rocksdb/blob/v11.8.1/include/rocksdb/table.h#L702-L731)
791    /// of the supported versions.
792    ///
793    /// Default: 7, which needs RocksDB 10.4.0 or newer to read. Lower it if
794    /// older readers have to open the files.
795    pub fn set_format_version(&mut self, version: i32) {
796        unsafe {
797            ffi::rocksdb_block_based_options_set_format_version(self.inner, version);
798        }
799    }
800
801    /// Use delta encoding to compress keys in blocks.
802    /// ReadOptions::pin_data requires this option to be disabled.
803    ///
804    /// Default: true
805    pub fn set_use_delta_encoding(&mut self, enable: bool) {
806        unsafe {
807            ffi::rocksdb_block_based_options_set_use_delta_encoding(
808                self.inner,
809                c_uchar::from(enable),
810            );
811        }
812    }
813
814    /// Number of keys between restart points for delta encoding of keys.
815    /// This parameter can be changed dynamically. Most clients should
816    /// leave this parameter alone. The minimum value allowed is 1. Any smaller
817    /// value will be silently overwritten with 1.
818    ///
819    /// Default: 16.
820    pub fn set_block_restart_interval(&mut self, interval: i32) {
821        unsafe {
822            ffi::rocksdb_block_based_options_set_block_restart_interval(self.inner, interval);
823        }
824    }
825
826    /// Same as block_restart_interval but used for the index block.
827    /// If you don't plan to run RocksDB before version 5.16 and you are
828    /// using `index_block_restart_interval` > 1, you should
829    /// probably set the `format_version` to >= 4 as it would reduce the index size.
830    ///
831    /// Default: 1.
832    pub fn set_index_block_restart_interval(&mut self, interval: i32) {
833        unsafe {
834            ffi::rocksdb_block_based_options_set_index_block_restart_interval(self.inner, interval);
835        }
836    }
837
838    /// Set the data block index type for point lookups:
839    ///  `DataBlockIndexType::BinarySearch` to use binary search within the data block.
840    ///  `DataBlockIndexType::BinaryAndHash` to use the data block hash index in combination with
841    ///  the normal binary search.
842    ///
843    /// The hash table utilization ratio is adjustable using [`set_data_block_hash_ratio`](#method.set_data_block_hash_ratio), which is
844    /// valid only when using `DataBlockIndexType::BinaryAndHash`.
845    ///
846    /// Default: `BinarySearch`
847    /// # Examples
848    ///
849    /// ```
850    /// use rust_rocksdb::{BlockBasedOptions, DataBlockIndexType, Options};
851    ///
852    /// let mut opts = Options::default();
853    /// let mut block_opts = BlockBasedOptions::default();
854    /// block_opts.set_data_block_index_type(DataBlockIndexType::BinaryAndHash);
855    /// block_opts.set_data_block_hash_ratio(0.85);
856    /// ```
857    pub fn set_data_block_index_type(&mut self, index_type: DataBlockIndexType) {
858        let index_t = index_type as i32;
859        unsafe {
860            ffi::rocksdb_block_based_options_set_data_block_index_type(self.inner, index_t);
861        }
862    }
863
864    /// Set the data block hash index utilization ratio.
865    ///
866    /// The smaller the utilization ratio, the less hash collisions happen, and so reduce the risk for a
867    /// point lookup to fall back to binary search due to the collisions. A small ratio means faster
868    /// lookup at the price of more space overhead.
869    ///
870    /// Default: 0.75
871    pub fn set_data_block_hash_ratio(&mut self, ratio: f64) {
872        unsafe {
873            ffi::rocksdb_block_based_options_set_data_block_hash_ratio(self.inner, ratio);
874        }
875    }
876
877    /// If false, place only prefixes in the filter, not whole keys.
878    ///
879    /// Defaults to true.
880    pub fn set_whole_key_filtering(&mut self, v: bool) {
881        unsafe {
882            ffi::rocksdb_block_based_options_set_whole_key_filtering(self.inner, c_uchar::from(v));
883        }
884    }
885
886    /// Use the specified checksum type.
887    /// Newly created table files will be protected with this checksum type.
888    /// Old table files will still be readable, even though they have different checksum type.
889    pub fn set_checksum_type(&mut self, checksum_type: ChecksumType) {
890        unsafe {
891            ffi::rocksdb_block_based_options_set_checksum(self.inner, checksum_type as c_char);
892        }
893    }
894
895    /// If true, generate Bloom/Ribbon filters that minimize memory internal
896    /// fragmentation.
897    /// See official [wiki](
898    /// https://github.com/facebook/rocksdb/wiki/RocksDB-Bloom-Filter#reducing-internal-fragmentation)
899    /// for more information.
900    ///
901    /// Default: true.
902    /// # Examples
903    ///
904    /// ```
905    /// use rust_rocksdb::BlockBasedOptions;
906    ///
907    /// let mut opts = BlockBasedOptions::default();
908    /// opts.set_bloom_filter(10.0, true);
909    /// opts.set_optimize_filters_for_memory(true);
910    /// ```
911    pub fn set_optimize_filters_for_memory(&mut self, v: bool) {
912        unsafe {
913            ffi::rocksdb_block_based_options_set_optimize_filters_for_memory(
914                self.inner,
915                c_uchar::from(v),
916            );
917        }
918    }
919
920    /// The tier of block-based tables whose top-level index into metadata
921    /// partitions will be pinned. Currently indexes and filters may be
922    /// partitioned.
923    ///
924    /// Note `cache_index_and_filter_blocks` must be true for this option to have
925    /// any effect. Otherwise any top-level index into metadata partitions would be
926    /// held in table reader memory, outside the block cache.
927    ///
928    /// Default: `BlockBasedPinningTier:Fallback`
929    ///
930    /// # Example
931    ///
932    /// ```
933    /// use rust_rocksdb::{BlockBasedOptions, BlockBasedPinningTier, Options};
934    ///
935    /// let mut opts = Options::default();
936    /// let mut block_opts = BlockBasedOptions::default();
937    /// block_opts.set_top_level_index_pinning_tier(BlockBasedPinningTier::FlushAndSimilar);
938    /// ```
939    pub fn set_top_level_index_pinning_tier(&mut self, tier: BlockBasedPinningTier) {
940        unsafe {
941            ffi::rocksdb_block_based_options_set_top_level_index_pinning_tier(
942                self.inner,
943                tier as c_int,
944            );
945        }
946    }
947
948    /// The tier of block-based tables whose metadata partitions will be pinned.
949    /// Currently indexes and filters may be partitioned.
950    ///
951    /// Default: `BlockBasedPinningTier:Fallback`
952    ///
953    /// # Example
954    ///
955    /// ```
956    /// use rust_rocksdb::{BlockBasedOptions, BlockBasedPinningTier, Options};
957    ///
958    /// let mut opts = Options::default();
959    /// let mut block_opts = BlockBasedOptions::default();
960    /// block_opts.set_partition_pinning_tier(BlockBasedPinningTier::FlushAndSimilar);
961    /// ```
962    pub fn set_partition_pinning_tier(&mut self, tier: BlockBasedPinningTier) {
963        unsafe {
964            ffi::rocksdb_block_based_options_set_partition_pinning_tier(self.inner, tier as c_int);
965        }
966    }
967
968    /// The tier of block-based tables whose unpartitioned metadata blocks will be
969    /// pinned.
970    ///
971    /// Note `cache_index_and_filter_blocks` must be true for this option to have
972    /// any effect. Otherwise the unpartitioned meta-blocks would be held in table
973    /// reader memory, outside the block cache.
974    ///
975    /// Default: `BlockBasedPinningTier:Fallback`
976    ///
977    /// # Example
978    ///
979    /// ```
980    /// use rust_rocksdb::{BlockBasedOptions, BlockBasedPinningTier, Options};
981    ///
982    /// let mut opts = Options::default();
983    /// let mut block_opts = BlockBasedOptions::default();
984    /// block_opts.set_unpartitioned_pinning_tier(BlockBasedPinningTier::FlushAndSimilar);
985    /// ```
986    pub fn set_unpartitioned_pinning_tier(&mut self, tier: BlockBasedPinningTier) {
987        unsafe {
988            ffi::rocksdb_block_based_options_set_unpartitioned_pinning_tier(
989                self.inner,
990                tier as c_int,
991            );
992        }
993    }
994
995    /// Align data blocks on lesser of page size and block size
996    pub fn get_block_align(&self) -> bool {
997        unsafe { ffi::rocksdb_block_based_options_get_block_align(self.inner) != 0 }
998    }
999
1000    /// Number of keys between restart points for delta encoding of keys. This parameter can
1001    /// be changed dynamically.  Most clients should leave this parameter alone.  The minimum
1002    /// value allowed is 1.  Any smaller value will be silently overwritten with 1.
1003    pub fn get_block_restart_interval(&self) -> c_int {
1004        unsafe { ffi::rocksdb_block_based_options_get_block_restart_interval(self.inner) }
1005    }
1006
1007    /// Approximate size of user data packed per block.  Note that the block size specified
1008    /// here corresponds to uncompressed data.  The actual size of the unit read from disk may
1009    /// be smaller if compression is enabled.  This parameter can be changed dynamically.
1010    pub fn get_block_size(&self) -> u64 {
1011        unsafe { ffi::rocksdb_block_based_options_get_block_size(self.inner) }
1012    }
1013
1014    /// This is used to close a block before it reaches the configured 'block_size'. If the
1015    /// percentage of free space in the current block is less than this specified number and
1016    /// adding a new record to the block will exceed the configured block size, then this
1017    /// block will be closed and the new record will be written to the next block.
1018    pub fn get_block_size_deviation(&self) -> c_int {
1019        unsafe { ffi::rocksdb_block_based_options_get_block_size_deviation(self.inner) }
1020    }
1021
1022    /// TODO(kailiu) Temporarily disable this feature by making the default value to be false.
1023    ///
1024    /// TODO(ajkr) we need to update names of variables controlling meta-block caching as they
1025    /// should now apply to range tombstone and compression dictionary meta-blocks, in
1026    /// addition to index and filter meta-blocks.
1027    ///
1028    /// Whether to put index/filter blocks in the block cache. When false, each "table reader"
1029    /// object will pre-load index/filter blocks during table initialization. Index and filter
1030    /// partition blocks always use block cache regardless of this option.
1031    pub fn get_cache_index_and_filter_blocks(&self) -> bool {
1032        unsafe {
1033            ffi::rocksdb_block_based_options_get_cache_index_and_filter_blocks(self.inner) != 0
1034        }
1035    }
1036
1037    /// If cache_index_and_filter_blocks is enabled, cache index and filter blocks with high
1038    /// priority. If set to true, depending on implementation of block cache, index, filter,
1039    /// and other metadata blocks may be less likely to be evicted than data blocks.
1040    pub fn get_cache_index_and_filter_blocks_with_high_priority(&self) -> bool {
1041        unsafe {
1042            ffi::rocksdb_block_based_options_get_cache_index_and_filter_blocks_with_high_priority(
1043                self.inner,
1044            ) != 0
1045        }
1046    }
1047
1048    /// Use the specified checksum type. Newly created table files will be protected with this
1049    /// checksum type. Old table files will still be readable, even though they have different
1050    /// checksum type.
1051    pub fn get_checksum(&self) -> c_int {
1052        unsafe { ffi::rocksdb_block_based_options_get_checksum(self.inner) }
1053    }
1054
1055    /// #entries/#buckets. It is valid only when data_block_hash_index_type is
1056    /// kDataBlockBinaryAndHash.
1057    pub fn set_data_block_hash_table_util_ratio(&mut self, val: f64) {
1058        unsafe {
1059            ffi::rocksdb_block_based_options_set_data_block_hash_table_util_ratio(self.inner, val);
1060        }
1061    }
1062
1063    /// Returns the value of the `data_block_hash_table_util_ratio` option.
1064    pub fn get_data_block_hash_table_util_ratio(&self) -> f64 {
1065        unsafe { ffi::rocksdb_block_based_options_get_data_block_hash_table_util_ratio(self.inner) }
1066    }
1067
1068    /// Returns the value of the `data_block_index_type` option.
1069    pub fn get_data_block_index_type(&self) -> c_int {
1070        unsafe { ffi::rocksdb_block_based_options_get_data_block_index_type(self.inner) }
1071    }
1072
1073    /// When both partitioned indexes and partitioned filters are enabled, this enables
1074    /// independent partitioning boundaries between the two. Most notably, this enables these
1075    /// metadata blocks to hit their target size much more accurately, as there is often a
1076    /// disparity between index sizes and filter sizes. This should reduce fragmentation and
1077    /// metadata overheads in the block cache, as well as treat blocks more fairly for cache
1078    /// eviction purposes.
1079    ///
1080    /// There are no SST format compatibility issues with this option. (All versions of
1081    /// RocksDB able to read partitioned filters are able to read decoupled partitioned
1082    /// filters.)
1083    ///
1084    /// decouple_partitioned_filters = true is the new default. This option is now DEPRECATED
1085    /// and might be ignored and/or removed in a future release.
1086    ///
1087    /// NOTE: decouple_partitioned_filters = false with partition_filters = true disables
1088    /// parallel compression (CompressionOptions::parallel_threads sanitized to 1).
1089    pub fn set_decouple_partitioned_filters(&mut self, val: bool) {
1090        unsafe {
1091            ffi::rocksdb_block_based_options_set_decouple_partitioned_filters(
1092                self.inner,
1093                c_uchar::from(val),
1094            );
1095        }
1096    }
1097
1098    /// Returns the value of the `decouple_partitioned_filters` option.
1099    pub fn get_decouple_partitioned_filters(&self) -> bool {
1100        unsafe {
1101            ffi::rocksdb_block_based_options_get_decouple_partitioned_filters(self.inner) != 0
1102        }
1103    }
1104
1105    /// If true, detect corruption during Bloom Filter (format_version >= 5) and Ribbon Filter
1106    /// construction.
1107    ///
1108    /// This is an extra check that is only useful in detecting software bugs or CPU+memory
1109    /// malfunction. Turning on this feature increases filter construction time by 30%.
1110    ///
1111    /// TODO: optimize this performance
1112    pub fn set_detect_filter_construct_corruption(&mut self, val: bool) {
1113        unsafe {
1114            ffi::rocksdb_block_based_options_set_detect_filter_construct_corruption(
1115                self.inner,
1116                c_uchar::from(val),
1117            );
1118        }
1119    }
1120
1121    /// Returns the value of the `detect_filter_construct_corruption` option.
1122    pub fn get_detect_filter_construct_corruption(&self) -> bool {
1123        unsafe {
1124            ffi::rocksdb_block_based_options_get_detect_filter_construct_corruption(self.inner) != 0
1125        }
1126    }
1127
1128    /// Store index blocks on disk in compressed format. Changing this option to false  will
1129    /// avoid the overhead of decompression if index blocks are evicted and read back
1130    pub fn set_enable_index_compression(&mut self, val: bool) {
1131        unsafe {
1132            ffi::rocksdb_block_based_options_set_enable_index_compression(
1133                self.inner,
1134                c_uchar::from(val),
1135            );
1136        }
1137    }
1138
1139    /// Returns the value of the `enable_index_compression` option.
1140    pub fn get_enable_index_compression(&self) -> bool {
1141        unsafe { ffi::rocksdb_block_based_options_get_enable_index_compression(self.inner) != 0 }
1142    }
1143
1144    /// EXPERIMENTAL
1145    ///
1146    /// Return an error Status if a user_defined_index_factory is configured, but there's no
1147    /// corresponding UDI block in the SST file being opened. When use_udi_as_primary_index is
1148    /// true, this check is automatically enforced (a missing UDI block is always an error in
1149    /// primary mode).
1150    pub fn set_fail_if_no_udi_on_open(&mut self, val: bool) {
1151        unsafe {
1152            ffi::rocksdb_block_based_options_set_fail_if_no_udi_on_open(
1153                self.inner,
1154                c_uchar::from(val),
1155            );
1156        }
1157    }
1158
1159    /// Returns the value of the `fail_if_no_udi_on_open` option.
1160    pub fn get_fail_if_no_udi_on_open(&self) -> bool {
1161        unsafe { ffi::rocksdb_block_based_options_get_fail_if_no_udi_on_open(self.inner) != 0 }
1162    }
1163
1164    /// We currently have these format versions: 0 - 1 -- No longer supported. Attempting to
1165    /// read files with these format versions will return an error. To upgrade, load the data
1166    /// with RocksDB >= 4.6.0 and < 11.0.0, then run a full compaction.
1167    /// - Can be read by RocksDB's versions since 3.10. Changes the way we encode compressed
1168    ///   blocks with LZ4, BZip2 and Zlib compression. If you don't plan to run RocksDB
1169    ///   before version 3.10, you should probably use this.
1170    /// - Can be read by RocksDB's versions since 5.15. Changes the way we encode the keys
1171    ///   in index blocks. If you don't plan to run RocksDB before version 5.15, you should
1172    ///   probably use this. This option only affects newly written tables. When reading
1173    ///   existing tables, the information about version is read from the footer.
1174    /// - Can be read by RocksDB's versions since 5.16. Changes the way we encode the values
1175    ///   in index blocks. If you don't plan to run RocksDB before version 5.16 and you are
1176    ///   using index_block_restart_interval > 1, you should probably use this as it would
1177    ///   reduce the index size. This option only affects newly written tables. When reading
1178    ///   existing tables, the information about version is read from the footer.
1179    /// - Can be read by RocksDB's versions since 6.6.0. Full and partitioned filters use a
1180    ///   generally faster and more accurate Bloom filter implementation, with a different
1181    ///   schema.
1182    /// - Modified the file footer and checksum matching so that SST data misplaced within
1183    ///   or between files is as likely to fail checksum verification as random corruption.
1184    ///   Also checksum-protects SST footer. Can be read by RocksDB versions >= 8.6.0.
1185    /// - Support for custom compression algorithms with a CompressionManager using a
1186    ///   non-built-in CompatibilityName(). See `compression_manager` in
1187    ///   ColumnFamilyOptions. Also changes the format of TableProperties field
1188    ///   `compression_name`. Can be read by RocksDB versions >= 10.4.0.
1189    ///
1190    /// Using the default setting of format_version is strongly recommended, so that available
1191    /// enhancements are adopted eventually and automatically. The default setting will only
1192    /// update to the latest after thorough production validation and sufficient time and
1193    /// number of releases have elapsed (6 months recommended) to ensure a clean
1194    /// downgrade/revert path for users who might only upgrade a few times per year.
1195    pub fn get_format_version(&self) -> u32 {
1196        unsafe { ffi::rocksdb_block_based_options_get_format_version(self.inner) }
1197    }
1198
1199    /// Same as block_restart_interval but used for the index block.
1200    pub fn get_index_block_restart_interval(&self) -> c_int {
1201        unsafe { ffi::rocksdb_block_based_options_get_index_block_restart_interval(self.inner) }
1202    }
1203
1204    /// Returns the value of the `index_block_search_type` option.
1205    pub fn get_index_block_search_type(&self) -> c_int {
1206        unsafe { ffi::rocksdb_block_based_options_get_index_block_search_type(self.inner) }
1207    }
1208
1209    /// Sets the `index_shortening` option.
1210    pub fn set_index_shortening(&mut self, val: c_int) {
1211        unsafe {
1212            ffi::rocksdb_block_based_options_set_index_shortening(self.inner, val);
1213        }
1214    }
1215
1216    /// Returns the value of the `index_shortening` option.
1217    pub fn get_index_shortening(&self) -> c_int {
1218        unsafe { ffi::rocksdb_block_based_options_get_index_shortening(self.inner) }
1219    }
1220
1221    /// Returns the value of the `index_type` option.
1222    pub fn get_index_type(&self) -> c_int {
1223        unsafe { ffi::rocksdb_block_based_options_get_index_type(self.inner) }
1224    }
1225
1226    /// RocksDB does auto-readahead for iterators on noticing more than two reads for a table
1227    /// file if user doesn't provide readahead_size. The readahead size starts at
1228    /// initial_auto_readahead_size and doubles on every additional read upto
1229    /// BlockBasedTableOptions.max_auto_readahead_size. max_auto_readahead_size can also be
1230    /// configured.
1231    ///
1232    /// Scenarios:
1233    /// - If initial_auto_readahead_size is set 0 then it will disabled the implicit auto
1234    ///   prefetching irrespective of max_auto_readahead_size.
1235    /// - If max_auto_readahead_size is set 0, it will disable the internal prefetching
1236    ///   irrespective of initial_auto_readahead_size.
1237    /// - If initial_auto_readahead_size > max_auto_readahead_size, then RocksDB will
1238    ///   sanitize the value of initial_auto_readahead_size to max_auto_readahead_size and
1239    ///   readahead_size will be max_auto_readahead_size.
1240    ///
1241    /// Value should be provided along with KB i.e. 8 * 1024 as it will prefetch the blocks.
1242    ///
1243    /// Default: 8 KB (8 * 1024).
1244    pub fn set_initial_auto_readahead_size(&mut self, val: usize) {
1245        unsafe {
1246            ffi::rocksdb_block_based_options_set_initial_auto_readahead_size(self.inner, val);
1247        }
1248    }
1249
1250    /// Returns the value of the `initial_auto_readahead_size` option.
1251    pub fn get_initial_auto_readahead_size(&self) -> usize {
1252        unsafe { ffi::rocksdb_block_based_options_get_initial_auto_readahead_size(self.inner) }
1253    }
1254
1255    /// RocksDB does auto-readahead for iterators on noticing more than two reads for a table
1256    /// file if user doesn't provide readahead_size. The readahead starts at
1257    /// BlockBasedTableOptions.initial_auto_readahead_size (default: 8KB) and doubles on every
1258    /// additional read upto max_auto_readahead_size and max_auto_readahead_size can be
1259    /// configured.
1260    ///
1261    /// Special Value: 0 - If max_auto_readahead_size is set 0 then it will disable the
1262    /// implicit auto prefetching. If max_auto_readahead_size provided is less than
1263    /// initial_auto_readahead_size, then RocksDB will sanitize the
1264    /// initial_auto_readahead_size and set it to max_auto_readahead_size.
1265    ///
1266    /// Value should be provided along with KB i.e. 256 * 1024 as it will prefetch the blocks.
1267    ///
1268    /// Found that 256 KB readahead size provides the best performance, based on experiments,
1269    /// for auto readahead. Experiment data is in PR #3282.
1270    ///
1271    /// Default: 256 KB (256 * 1024).
1272    pub fn set_max_auto_readahead_size(&mut self, val: usize) {
1273        unsafe {
1274            ffi::rocksdb_block_based_options_set_max_auto_readahead_size(self.inner, val);
1275        }
1276    }
1277
1278    /// Returns the value of the `max_auto_readahead_size` option.
1279    pub fn get_max_auto_readahead_size(&self) -> usize {
1280        unsafe { ffi::rocksdb_block_based_options_get_max_auto_readahead_size(self.inner) }
1281    }
1282
1283    /// Target block size for partitioned metadata. Currently applied to indexes when
1284    /// kTwoLevelIndexSearch is used and to filters when partition_filters is used. When
1285    /// decouple_partitioned_filters=false (original behavior), there is much more deviation
1286    /// from this target size. See the comment on decouple_partitioned_filters.
1287    pub fn get_metadata_block_size(&self) -> u64 {
1288        unsafe { ffi::rocksdb_block_based_options_get_metadata_block_size(self.inner) }
1289    }
1290
1291    /// Disable block cache. If this is set to true, then no block cache will be configured
1292    /// (block_cache reset to nullptr).
1293    ///
1294    /// This option should not be used with SetOptions.
1295    pub fn get_no_block_cache(&self) -> bool {
1296        unsafe { ffi::rocksdb_block_based_options_get_no_block_cache(self.inner) != 0 }
1297    }
1298
1299    /// RocksDB does auto-readahead for iterators on noticing more than two reads for a table
1300    /// file if user doesn't provide readahead_size and reads are sequential.
1301    /// num_file_reads_for_auto_readahead indicates after how many sequential reads internal
1302    /// auto prefetching should be start.
1303    ///
1304    /// For example, if value is 2 then after reading 2 sequential data blocks on third data
1305    /// block prefetching will start. If set 0, it will start prefetching from the first read.
1306    ///
1307    /// This parameter can be changed dynamically by
1308    /// DB::SetOptions({{"block_based_table_factory",
1309    /// "{num_file_reads_for_auto_readahead=0;}"}}));
1310    ///
1311    /// Changing the value dynamically will only affect files opened after the change.
1312    ///
1313    /// Default: 2
1314    pub fn set_num_file_reads_for_auto_readahead(&mut self, val: u64) {
1315        unsafe {
1316            ffi::rocksdb_block_based_options_set_num_file_reads_for_auto_readahead(self.inner, val);
1317        }
1318    }
1319
1320    /// Returns the value of the `num_file_reads_for_auto_readahead` option.
1321    pub fn get_num_file_reads_for_auto_readahead(&self) -> u64 {
1322        unsafe {
1323            ffi::rocksdb_block_based_options_get_num_file_reads_for_auto_readahead(self.inner)
1324        }
1325    }
1326
1327    /// Option to generate Bloom/Ribbon filters that minimize memory internal fragmentation.
1328    ///
1329    /// When false, malloc_usable_size is not available, or format_version < 5, filters are
1330    /// generated without regard to internal fragmentation when loaded into memory (historical
1331    /// behavior). When true (and malloc_usable_size is available and format_version >= 5),
1332    /// then filters are generated to "round up" and "round down" their sizes to minimize
1333    /// internal fragmentation when loaded into memory, assuming the reading DB has the same
1334    /// memory allocation characteristics as the generating DB. This option does not break
1335    /// forward or backward compatibility.
1336    ///
1337    /// While individual filters will vary in bits/key and false positive rate when setting is
1338    /// true, the implementation attempts to maintain a weighted average FP rate for filters
1339    /// consistent with this option set to false.
1340    ///
1341    /// With Jemalloc for example, this setting is expected to save about 10% of the memory
1342    /// footprint and block cache charge of filters, while increasing disk usage of filters by
1343    /// about 1-2% due to encoding efficiency losses with variance in bits/key.
1344    ///
1345    /// NOTE: Because some memory counted by block cache might be unmapped pages within
1346    /// internal fragmentation, this option can increase observed RSS memory usage. With
1347    /// cache_index_and_filter_blocks=true, this option makes the block cache better at using
1348    /// space it is allowed. (These issues should not arise with partitioned filters.)
1349    ///
1350    /// NOTE: Set to false if you do not trust malloc_usable_size. When set to true, RocksDB
1351    /// might access an allocated memory object beyond its original size if malloc_usable_size
1352    /// says it is safe to do so. While this can be considered bad practice, it should not
1353    /// produce undefined behavior unless malloc_usable_size is buggy or broken.
1354    pub fn get_optimize_filters_for_memory(&self) -> bool {
1355        unsafe { ffi::rocksdb_block_based_options_get_optimize_filters_for_memory(self.inner) != 0 }
1356    }
1357
1358    /// Note: currently this option requires kTwoLevelIndexSearch to be set as well.
1359    /// TODO(myabandeh): remove the note above once the limitation is lifted Use partitioned
1360    /// full filters for each SST file. This option is incompatible with block-based filters.
1361    /// Filter partition blocks use block cache even when cache_index_and_filter_blocks=false.
1362    pub fn get_partition_filters(&self) -> bool {
1363        unsafe { ffi::rocksdb_block_based_options_get_partition_filters(self.inner) != 0 }
1364    }
1365
1366    /// DEPRECATED: This option will be removed in a future version. For now, this option
1367    /// still takes effect by updating each of the following variables that has the default
1368    /// value, `PinningTier::kFallback`:
1369    ///
1370    /// - `MetadataCacheOptions::partition_pinning`
1371    /// - `MetadataCacheOptions::unpartitioned_pinning`
1372    ///
1373    /// The updated value is chosen as follows:
1374    ///
1375    /// - `pin_l0_filter_and_index_blocks_in_cache == false` -> `PinningTier::kNone`
1376    /// - `pin_l0_filter_and_index_blocks_in_cache == true` ->
1377    ///   `PinningTier::kFlushedAndSimilar`
1378    ///
1379    /// To migrate away from this flag, explicitly configure `MetadataCacheOptions` as
1380    /// described above.
1381    ///
1382    /// if cache_index_and_filter_blocks is true and the below is true, then filter and index
1383    /// blocks are stored in the cache, but a reference is held in the "table reader" object
1384    /// so the blocks are pinned and only evicted from cache when the table reader is freed.
1385    pub fn get_pin_l0_filter_and_index_blocks_in_cache(&self) -> bool {
1386        unsafe {
1387            ffi::rocksdb_block_based_options_get_pin_l0_filter_and_index_blocks_in_cache(self.inner)
1388                != 0
1389        }
1390    }
1391
1392    /// DEPRECATED: This option will be removed in a future version. For now, this option
1393    /// still takes effect by updating `MetadataCacheOptions::top_level_index_pinning` when it
1394    /// has the default value, `PinningTier::kFallback`.
1395    ///
1396    /// The updated value is chosen as follows:
1397    ///
1398    /// - `pin_top_level_index_and_filter == false` -> `PinningTier::kNone`
1399    /// - `pin_top_level_index_and_filter == true` -> `PinningTier::kAll`
1400    ///
1401    /// To migrate away from this flag, explicitly configure `MetadataCacheOptions` as
1402    /// described above.
1403    ///
1404    /// If cache_index_and_filter_blocks is true and the below is true, then the top-level
1405    /// index of partitioned filter and index blocks are stored in the cache, but a reference
1406    /// is held in the "table reader" object so the blocks are pinned and only evicted from
1407    /// cache when the table reader is freed. This is not limited to l0 in LSM tree.
1408    pub fn get_pin_top_level_index_and_filter(&self) -> bool {
1409        unsafe {
1410            ffi::rocksdb_block_based_options_get_pin_top_level_index_and_filter(self.inner) != 0
1411        }
1412    }
1413
1414    /// Sets the `prepopulate_block_cache` option.
1415    pub fn set_prepopulate_block_cache(&mut self, val: c_int) {
1416        unsafe {
1417            ffi::rocksdb_block_based_options_set_prepopulate_block_cache(self.inner, val);
1418        }
1419    }
1420
1421    /// Returns the value of the `prepopulate_block_cache` option.
1422    pub fn get_prepopulate_block_cache(&self) -> c_int {
1423        unsafe { ffi::rocksdb_block_based_options_get_prepopulate_block_cache(self.inner) }
1424    }
1425
1426    /// If used, For every data block we load into memory, we will create a bitmap of size
1427    /// ((block_size / `read_amp_bytes_per_bit`) / 8) bytes. This bitmap will be used to
1428    /// figure out the percentage we actually read of the blocks.
1429    ///
1430    /// When this feature is used Tickers::READ_AMP_ESTIMATE_USEFUL_BYTES and
1431    /// Tickers::READ_AMP_TOTAL_READ_BYTES can be used to calculate the read amplification
1432    /// using this formula (READ_AMP_TOTAL_READ_BYTES / READ_AMP_ESTIMATE_USEFUL_BYTES)
1433    ///
1434    /// value  =>  memory usage (percentage of loaded blocks memory) 1      =>  12.50 % 2
1435    /// =>  06.25 % 4      =>  03.12 % 8      =>  01.56 % 16     =>  00.78 %
1436    ///
1437    /// Note: This number must be a power of 2, if not it will be sanitized to be the next
1438    /// lowest power of 2, for example a value of 7 will be treated as 4, a value of 19 will
1439    /// be treated as 16.
1440    ///
1441    /// Default: 0 (disabled)
1442    pub fn set_read_amp_bytes_per_bit(&mut self, val: u32) {
1443        unsafe {
1444            ffi::rocksdb_block_based_options_set_read_amp_bytes_per_bit(self.inner, val);
1445        }
1446    }
1447
1448    /// Returns the value of the `read_amp_bytes_per_bit` option.
1449    pub fn get_read_amp_bytes_per_bit(&self) -> u32 {
1450        unsafe { ffi::rocksdb_block_based_options_get_read_amp_bytes_per_bit(self.inner) }
1451    }
1452
1453    /// When true, data blocks store keys and values separately. Keys are stored at the
1454    /// beginning of the block, followed by values at the end. This can improve read
1455    /// performance at a cost of a varint per restart interval (~1 bit per key by default), in
1456    /// addition to improving compression. Small values or low block_restart_interval may
1457    /// prefer to set this as false.
1458    ///
1459    /// Default: false
1460    pub fn get_separate_key_value_in_data_block(&self) -> bool {
1461        unsafe {
1462            ffi::rocksdb_block_based_options_get_separate_key_value_in_data_block(self.inner) != 0
1463        }
1464    }
1465
1466    /// Align data blocks on super block alignment. Avoid a data block split across super
1467    /// block boundaries. Works with/without compression.
1468    ///
1469    /// Here a "super block" refers to an aligned unit of underlying Filesystem storage for
1470    /// which there is an extra cost when a random read involves two such super blocks instead
1471    /// of just one. Configuring that size here suggests inserting padding in the SST file to
1472    /// avoid a single SST block splitting across two super blocks. Only power-of-two sizes
1473    /// are supported. See also super_block_alignment_space_overhead_ratio. Default to 0,
1474    /// which means super block alignment is disabled.
1475    ///
1476    /// Super block alignment size. Default to 0, which means super block alignment is
1477    /// disabled. If it is enabled, it needs to be a power of 2 and higher than block size.
1478    pub fn set_super_block_alignment_size(&mut self, val: usize) {
1479        unsafe {
1480            ffi::rocksdb_block_based_options_set_super_block_alignment_size(self.inner, val);
1481        }
1482    }
1483
1484    /// Returns the value of the `super_block_alignment_size` option.
1485    pub fn get_super_block_alignment_size(&self) -> usize {
1486        unsafe { ffi::rocksdb_block_based_options_get_super_block_alignment_size(self.inner) }
1487    }
1488
1489    /// This option constrols the storage space overhead of super block alignment. It is used
1490    /// to calculate the max padding size allowed for super block alignment. It is calculated
1491    /// in this way. If super_block_alignment_size is 2MB, and
1492    /// super_block_alignment_overhead_ratio is 128, then the max padding size allowed for
1493    /// super block alignment is 2MB / 128 = 16KB. Note that, when it is set to 0, super block
1494    /// alignment is disabled.
1495    pub fn set_super_block_alignment_space_overhead_ratio(&mut self, val: usize) {
1496        unsafe {
1497            ffi::rocksdb_block_based_options_set_super_block_alignment_space_overhead_ratio(
1498                self.inner, val,
1499            );
1500        }
1501    }
1502
1503    /// Returns the value of the `super_block_alignment_space_overhead_ratio` option.
1504    pub fn get_super_block_alignment_space_overhead_ratio(&self) -> usize {
1505        unsafe {
1506            ffi::rocksdb_block_based_options_get_super_block_alignment_space_overhead_ratio(
1507                self.inner,
1508            )
1509        }
1510    }
1511
1512    /// Coefficient of variation (CV) threshold used to determine if keys in an index block
1513    /// are uniformly distributed. Lower CV means more "uniform", and the more likely
1514    /// interpolation search will outperform binary search.
1515    ///
1516    /// On the write path, if the CV of key gaps in an index block is less than this
1517    /// threshold, the "is_uniform" hint is set in that block's footer. To disable (i.e.
1518    /// always have "is_uniform=false"), set value to -1.
1519    ///
1520    /// On the read path, if `BlockSearchType::kAuto` is set, then it will use the is_uniform
1521    /// hint to select an appropriate search algorithm for the block.
1522    ///
1523    /// NOTE: Currently only supports index blocks. May update to include data blocks in the
1524    /// future.
1525    pub fn get_uniform_cv_threshold(&self) -> f64 {
1526        unsafe { ffi::rocksdb_block_based_options_get_uniform_cv_threshold(self.inner) }
1527    }
1528
1529    /// Use delta encoding to compress keys in blocks. ReadOptions::pin_data requires this
1530    /// option to be disabled.
1531    ///
1532    /// Default: true
1533    pub fn get_use_delta_encoding(&self) -> bool {
1534        unsafe { ffi::rocksdb_block_based_options_get_use_delta_encoding(self.inner) != 0 }
1535    }
1536
1537    /// EXPERIMENTAL
1538    ///
1539    /// When true and user_defined_index_factory is set, the UDI becomes the primary index for
1540    /// reads. All reads (including internal operations like compaction and VerifyChecksum)
1541    /// automatically route through the UDI without needing ReadOptions::table_index_factory.
1542    ///
1543    /// Both the standard binary search index and the UDI are always fully built. The standard
1544    /// index serves as a safety fallback (e.g., for backup/restore or rollback to a non-UDI
1545    /// configuration). A future refactor will extract the index abstraction to allow skipping
1546    /// the standard index build when the UDI is primary.
1547    ///
1548    /// When the UDI is primary:
1549    /// - All reads automatically use the UDI (ReadOptions::table_index_factory does not
1550    ///   need to be set)
1551    /// - Partitioned index (kTwoLevelIndexSearch) and partitioned filters are incompatible
1552    ///   with this option
1553    /// - fail_if_no_udi_on_open is automatically enforced to prevent silent data loss if
1554    ///   these SSTs are opened without UDI support
1555    ///
1556    /// Recommended migration path:
1557    ///
1558    /// - Deploy with user_defined_index_factory set but use_udi_as_primary_index=false
1559    ///   (secondary mode). New SSTs are written with both indexes. Reads use the standard
1560    ///   index by default.
1561    ///
1562    /// - Validate reads through the UDI by setting ReadOptions::table_index_factory on a
1563    ///   subset of reads.
1564    ///
1565    /// - Compact the entire DB to rewrite all pre-existing SSTs with both indexes. All SSTs
1566    ///   must have a UDI block before proceeding.
1567    ///
1568    /// - Enable use_udi_as_primary_index=true. All reads use the UDI.
1569    ///
1570    /// Rollback: set use_udi_as_primary_index=false. Since the standard index is always fully
1571    /// populated, SSTs are immediately readable through the standard index. No compaction is
1572    /// required. All reads immediately revert to the standard index path.
1573    ///
1574    /// Backup/restore: the user_defined_index_factory is a shared_ptr that cannot survive
1575    /// Options serialization (e.g., GetStringFromDBOptions). Since the standard index is
1576    /// always fully populated, a restored DB can be opened and read without the factory
1577    /// (reads fall back to the standard index). Set the factory when opening the restored DB
1578    /// to resume using the UDI.
1579    ///
1580    /// Default: false (UDI is built alongside the standard index as a secondary)
1581    pub fn set_use_udi_as_primary_index(&mut self, val: bool) {
1582        unsafe {
1583            ffi::rocksdb_block_based_options_set_use_udi_as_primary_index(
1584                self.inner,
1585                c_uchar::from(val),
1586            );
1587        }
1588    }
1589
1590    /// Returns the value of the `use_udi_as_primary_index` option.
1591    pub fn get_use_udi_as_primary_index(&self) -> bool {
1592        unsafe { ffi::rocksdb_block_based_options_get_use_udi_as_primary_index(self.inner) != 0 }
1593    }
1594
1595    /// EXPERIMENTAL
1596    ///
1597    /// Builds a user defined index into every new SST file, using the factory named by
1598    /// `value`.
1599    ///
1600    /// `value` goes through the `UserDefinedIndexFactory` object registry, so it is either a
1601    /// registered id on its own or an id followed by that factory's own settings, in the
1602    /// usual `id=name; option=value; ...` form. `trie_index` is the only factory RocksDB
1603    /// registers itself.
1604    ///
1605    /// The factory replaces any set earlier. Reads still go through the standard index unless
1606    /// [`Self::set_use_udi_as_primary_index`] is on or
1607    /// [`ReadOptions::set_table_index_factory_from_string`] selects the UDI for that read.
1608    ///
1609    /// # Errors
1610    ///
1611    /// Returns an error if `value` names no registered factory, or carries settings that
1612    /// factory rejects. Either way the previously configured factory is cleared first.
1613    pub fn set_user_defined_index_factory_from_string(
1614        &mut self,
1615        value: impl AsRef<str>,
1616    ) -> Result<(), Error> {
1617        let value = value.as_ref();
1618        unsafe {
1619            ffi_try!(
1620                ffi::rocksdb_block_based_options_set_user_defined_index_factory_from_string(
1621                    self.inner,
1622                    value.as_ptr().cast::<c_char>(),
1623                    value.len(),
1624                )
1625            );
1626        }
1627        Ok(())
1628    }
1629
1630    /// Name of the configured user defined index factory, or `None` when there is none.
1631    ///
1632    /// This is the factory's registered id, not the full string passed to
1633    /// [`Self::set_user_defined_index_factory_from_string`].
1634    pub fn get_user_defined_index_factory_name(&self) -> Option<String> {
1635        let mut len: size_t = 0;
1636        let name = unsafe {
1637            ffi::rocksdb_block_based_options_get_user_defined_index_factory_name(
1638                self.inner.cast_const(),
1639                &raw mut len,
1640            )
1641        };
1642        if name.is_null() {
1643            return None;
1644        }
1645        Some(unsafe { borrowed_string(name, len) })
1646    }
1647
1648    /// Drops the user defined index factory, so new SST files carry only the standard index.
1649    ///
1650    /// Files already written keep their UDI block, and stay readable through the standard
1651    /// index.
1652    pub fn clear_user_defined_index_factory(&mut self) {
1653        unsafe {
1654            ffi::rocksdb_block_based_options_clear_user_defined_index_factory(self.inner);
1655        }
1656    }
1657
1658    /// Verify that decompressing the compressed block gives back the input. This is a
1659    /// verification mode that we use to detect bugs in compression algorithms.
1660    pub fn set_verify_compression(&mut self, val: bool) {
1661        unsafe {
1662            ffi::rocksdb_block_based_options_set_verify_compression(self.inner, c_uchar::from(val));
1663        }
1664    }
1665
1666    /// Returns the value of the `verify_compression` option.
1667    pub fn get_verify_compression(&self) -> bool {
1668        unsafe { ffi::rocksdb_block_based_options_get_verify_compression(self.inner) != 0 }
1669    }
1670
1671    /// If true, place whole keys in the filter (not just prefixes). This must generally be
1672    /// true for gets to be efficient.
1673    pub fn get_whole_key_filtering(&self) -> bool {
1674        unsafe { ffi::rocksdb_block_based_options_get_whole_key_filtering(self.inner) != 0 }
1675    }
1676
1677    /// Align data blocks on lesser of page size and block size.
1678    pub fn set_block_align(&mut self, val: bool) {
1679        unsafe {
1680            ffi::rocksdb_block_based_options_set_block_align(self.inner, c_uchar::from(val));
1681        }
1682    }
1683
1684    /// This is used to close a block before it reaches the configured 'block_size'. If the
1685    /// percentage of free space in the current block is less than this specified number and
1686    /// adding a new record to the block will exceed the configured block size, then this
1687    /// block will be closed and the new record will be written to the next block.
1688    pub fn set_block_size_deviation(&mut self, val: c_int) {
1689        unsafe {
1690            ffi::rocksdb_block_based_options_set_block_size_deviation(self.inner, val);
1691        }
1692    }
1693
1694    /// When true, data blocks store keys and values separately. Keys are stored at the
1695    /// beginning of the block, followed by values at the end. This can improve read
1696    /// performance at a cost of a varint per restart interval (~1 bit per key by default), in
1697    /// addition to improving compression. Small values or low block_restart_interval may
1698    /// prefer to set this as false.
1699    ///
1700    /// Default: false.
1701    pub fn set_separate_key_value_in_data_block(&mut self, val: bool) {
1702        unsafe {
1703            ffi::rocksdb_block_based_options_set_separate_key_value_in_data_block(
1704                self.inner,
1705                c_uchar::from(val),
1706            );
1707        }
1708    }
1709}
1710
1711impl Default for BlockBasedOptions {
1712    fn default() -> Self {
1713        let block_opts = unsafe { ffi::rocksdb_block_based_options_create() };
1714        assert!(
1715            !block_opts.is_null(),
1716            "Could not create RocksDB block based options"
1717        );
1718
1719        Self {
1720            inner: block_opts,
1721            outlive: BlockBasedOptionsMustOutliveDB::default(),
1722        }
1723    }
1724}
1725
1726impl CuckooTableOptions {
1727    /// Determines the utilization of hash tables. Smaller values
1728    /// result in larger hash tables with fewer collisions.
1729    /// Default: 0.9
1730    pub fn set_hash_ratio(&mut self, ratio: f64) {
1731        unsafe {
1732            ffi::rocksdb_cuckoo_options_set_hash_ratio(self.inner, ratio);
1733        }
1734    }
1735
1736    /// A property used by builder to determine the depth to go to
1737    /// to search for a path to displace elements in case of
1738    /// collision. See Builder.MakeSpaceForKey method. Higher
1739    /// values result in more efficient hash tables with fewer
1740    /// lookups but take more time to build.
1741    /// Default: 100
1742    pub fn set_max_search_depth(&mut self, depth: u32) {
1743        unsafe {
1744            ffi::rocksdb_cuckoo_options_set_max_search_depth(self.inner, depth);
1745        }
1746    }
1747
1748    /// In case of collision while inserting, the builder
1749    /// attempts to insert in the next cuckoo_block_size
1750    /// locations before skipping over to the next Cuckoo hash
1751    /// function. This makes lookups more cache friendly in case
1752    /// of collisions.
1753    /// Default: 5
1754    pub fn set_cuckoo_block_size(&mut self, size: u32) {
1755        unsafe {
1756            ffi::rocksdb_cuckoo_options_set_cuckoo_block_size(self.inner, size);
1757        }
1758    }
1759
1760    /// If this option is enabled, user key is treated as uint64_t and its value
1761    /// is used as hash value directly. This option changes builder's behavior.
1762    /// Reader ignore this option and behave according to what specified in
1763    /// table property.
1764    /// Default: false
1765    pub fn set_identity_as_first_hash(&mut self, flag: bool) {
1766        unsafe {
1767            ffi::rocksdb_cuckoo_options_set_identity_as_first_hash(self.inner, c_uchar::from(flag));
1768        }
1769    }
1770
1771    /// If this option is set to true, module is used during hash calculation.
1772    /// This often yields better space efficiency at the cost of performance.
1773    /// If this option is set to false, # of entries in table is constrained to
1774    /// be power of two, and bit and is used to calculate hash, which is faster in general.
1775    /// Default: true
1776    pub fn set_use_module_hash(&mut self, flag: bool) {
1777        unsafe {
1778            ffi::rocksdb_cuckoo_options_set_use_module_hash(self.inner, c_uchar::from(flag));
1779        }
1780    }
1781
1782    /// In case of collision while inserting, the builder attempts to insert in the next
1783    /// cuckoo_block_size locations before skipping over to the next Cuckoo hash function.
1784    /// This makes lookups more cache friendly in case of collisions.
1785    pub fn get_cuckoo_block_size(&self) -> u32 {
1786        unsafe { ffi::rocksdb_cuckoo_options_get_cuckoo_block_size(self.inner) }
1787    }
1788
1789    /// @hash_table_ratio: the desired utilization of the hash table used for prefix hashing.
1790    /// hash_table_ratio = number of prefixes / #buckets in the hash table
1791    pub fn set_hash_table_ratio(&mut self, val: f64) {
1792        unsafe {
1793            ffi::rocksdb_cuckoo_options_set_hash_table_ratio(self.inner, val);
1794        }
1795    }
1796
1797    /// Returns the value of the `hash_table_ratio` option.
1798    pub fn get_hash_table_ratio(&self) -> f64 {
1799        unsafe { ffi::rocksdb_cuckoo_options_get_hash_table_ratio(self.inner) }
1800    }
1801
1802    /// If this option is enabled, user key is treated as uint64_t and its value is used as
1803    /// hash value directly. This option changes builder's behavior. Reader ignore this option
1804    /// and behave according to what specified in table property.
1805    pub fn get_identity_as_first_hash(&self) -> bool {
1806        unsafe { ffi::rocksdb_cuckoo_options_get_identity_as_first_hash(self.inner) != 0 }
1807    }
1808
1809    /// A property used by builder to determine the depth to go to to search for a path to
1810    /// displace elements in case of collision. See Builder.MakeSpaceForKey method. Higher
1811    /// values result in more efficient hash tables with fewer lookups but take more time to
1812    /// build.
1813    pub fn get_max_search_depth(&self) -> u32 {
1814        unsafe { ffi::rocksdb_cuckoo_options_get_max_search_depth(self.inner) }
1815    }
1816
1817    /// If this option is set to true, module is used during hash calculation. This often
1818    /// yields better space efficiency at the cost of performance. If this option is set to
1819    /// false, # of entries in table is constrained to be power of two, and bit and is used to
1820    /// calculate hash, which is faster in general.
1821    pub fn get_use_module_hash(&self) -> bool {
1822        unsafe { ffi::rocksdb_cuckoo_options_get_use_module_hash(self.inner) != 0 }
1823    }
1824}
1825
1826impl Default for CuckooTableOptions {
1827    fn default() -> Self {
1828        let opts = unsafe { ffi::rocksdb_cuckoo_options_create() };
1829        assert!(!opts.is_null(), "Could not create RocksDB cuckoo options");
1830
1831        Self { inner: opts }
1832    }
1833}
1834
1835// Verbosity of the LOG.
1836#[derive(Debug, Copy, Clone, PartialEq, Eq)]
1837#[repr(i32)]
1838pub enum LogLevel {
1839    Debug = 0,
1840    Info,
1841    Warn,
1842    Error,
1843    Fatal,
1844    Header,
1845}
1846
1847impl LogLevel {
1848    pub(crate) fn try_from_raw(raw: i32) -> Option<Self> {
1849        match raw {
1850            n if n == LogLevel::Debug as i32 => Some(LogLevel::Debug),
1851            n if n == LogLevel::Info as i32 => Some(LogLevel::Info),
1852            n if n == LogLevel::Warn as i32 => Some(LogLevel::Warn),
1853            n if n == LogLevel::Error as i32 => Some(LogLevel::Error),
1854            n if n == LogLevel::Fatal as i32 => Some(LogLevel::Fatal),
1855            n if n == LogLevel::Header as i32 => Some(LogLevel::Header),
1856            _ => None,
1857        }
1858    }
1859}
1860
1861impl Options {
1862    /// Constructs the DBOptions and ColumnFamilyDescriptors by loading the
1863    /// latest RocksDB options file stored in the specified rocksdb database.
1864    ///
1865    /// *IMPORTANT*:
1866    /// ROCKSDB DOES NOT STORE cf ttl in the options file. If you have set it via
1867    /// [`ColumnFamilyDescriptor::new_with_ttl`] then you need to set it again after loading the options file.
1868    /// Tll will be set to [`ColumnFamilyTtl::Disabled`] for all column families for your safety.
1869    pub fn load_latest<P: AsRef<Path>>(
1870        path: P,
1871        env: Env,
1872        ignore_unknown_options: bool,
1873        cache: Cache,
1874    ) -> Result<(Options, Vec<ColumnFamilyDescriptor>), Error> {
1875        let path = to_cpath(path)?;
1876        let mut db_options: *mut ffi::rocksdb_options_t = null_mut();
1877        let mut num_column_families: usize = 0;
1878        let mut column_family_names: *mut *mut c_char = null_mut();
1879        let mut column_family_options: *mut *mut ffi::rocksdb_options_t = null_mut();
1880        unsafe {
1881            ffi_try!(ffi::rocksdb_load_latest_options(
1882                path.as_ptr(),
1883                env.0.inner,
1884                ignore_unknown_options,
1885                cache.0.inner.as_ptr(),
1886                &raw mut db_options,
1887                &raw mut num_column_families,
1888                &raw mut column_family_names,
1889                &raw mut column_family_options,
1890            ));
1891        }
1892        let options = Options {
1893            inner: db_options,
1894            outlive: OptionsMustOutliveDB::default(),
1895        };
1896        // read_column_descriptors frees column_family_names and the column_family_options array.
1897        // We can't call rocksdb_load_latest_options_destroy because it also frees options, and
1898        // the individual `column_family_options` pointers. We want to return them.
1899        let column_families = unsafe {
1900            Options::read_column_descriptors(
1901                num_column_families,
1902                column_family_names,
1903                column_family_options,
1904            )
1905        };
1906        Ok((options, column_families))
1907    }
1908
1909    /// Constructs a new `DBOptions` from `self` and a string `opts_str` with the syntax detailed in the blogpost
1910    /// [Reading RocksDB options from a file](https://rocksdb.org/blog/2015/02/24/reading-rocksdb-options-from-a-file.html)
1911    pub fn get_options_from_string<S: AsRef<str>>(
1912        &mut self,
1913        opts_str: S,
1914    ) -> Result<Options, Error> {
1915        // create the rocksdb_options_t and immediately wrap it so we don't forget to free it
1916        let options = Options {
1917            inner: unsafe { ffi::rocksdb_options_create() },
1918            outlive: OptionsMustOutliveDB::default(),
1919        };
1920
1921        let opts_cstr = opts_str.as_ref().into_c_string().map_err(|e| {
1922            Error::new(format!(
1923                "options string must not contain NUL (0x00) bytes: {e}"
1924            ))
1925        })?;
1926        unsafe {
1927            ffi_try!(ffi::rocksdb_get_options_from_string(
1928                self.inner.cast_const(),
1929                opts_cstr.as_ptr(),
1930                options.inner,
1931            ));
1932        }
1933        Ok(options)
1934    }
1935
1936    /// Reads column descriptors from C pointers. This frees the `column_family_names` and
1937    /// `column_family_options` arrays, and the strings contained in `column_family_names`. It does
1938    /// *not* free the `rocksdb_options_t*` pointers contained in `column_family_options`.
1939    #[inline]
1940    unsafe fn read_column_descriptors(
1941        num_column_families: usize,
1942        column_family_names: *mut *mut c_char,
1943        column_family_options: *mut *mut ffi::rocksdb_options_t,
1944    ) -> Vec<ColumnFamilyDescriptor> {
1945        let column_family_names_iter = unsafe {
1946            slice::from_raw_parts(column_family_names, num_column_families)
1947                .iter()
1948                .map(|ptr| from_cstr_and_free(*ptr))
1949        };
1950        let column_family_options_iter = unsafe {
1951            slice::from_raw_parts(column_family_options, num_column_families)
1952                .iter()
1953                .map(|ptr| Options {
1954                    inner: *ptr,
1955                    outlive: OptionsMustOutliveDB::default(),
1956                })
1957        };
1958        let column_descriptors = column_family_names_iter
1959            .zip(column_family_options_iter)
1960            .map(|(name, options)| ColumnFamilyDescriptor {
1961                name,
1962                options,
1963                ttl: ColumnFamilyTtl::Disabled,
1964            })
1965            .collect::<Vec<_>>();
1966
1967        // free the arrays
1968        unsafe {
1969            // we freed each string in the column_family_names array using from_cstr_and_free
1970            ffi::rocksdb_free(column_family_names as *mut c_void);
1971            // we don't want to free the contents of this array because we return it
1972            ffi::rocksdb_free(column_family_options as *mut c_void);
1973            column_descriptors
1974        }
1975    }
1976
1977    /// By default, RocksDB uses only one background thread for flush and
1978    /// compaction. Calling this function will set it up such that total of
1979    /// `total_threads` is used. Good value for `total_threads` is the number of
1980    /// cores. You almost definitely want to call this function if your system is
1981    /// bottlenecked by RocksDB.
1982    ///
1983    /// # Examples
1984    ///
1985    /// ```
1986    /// use rust_rocksdb::Options;
1987    ///
1988    /// let mut opts = Options::default();
1989    /// opts.increase_parallelism(3);
1990    /// ```
1991    pub fn increase_parallelism(&mut self, parallelism: i32) {
1992        unsafe {
1993            ffi::rocksdb_options_increase_parallelism(self.inner, parallelism);
1994        }
1995    }
1996
1997    /// Optimize level style compaction.
1998    ///
1999    /// Default values for some parameters in `Options` are not optimized for heavy
2000    /// workloads and big datasets, which means you might observe write stalls under
2001    /// some conditions.
2002    ///
2003    /// This can be used as one of the starting points for tuning RocksDB options in
2004    /// such cases.
2005    ///
2006    /// Internally, it sets `write_buffer_size`, `min_write_buffer_number_to_merge`,
2007    /// `max_write_buffer_number`, `level0_file_num_compaction_trigger`,
2008    /// `target_file_size_base`, `max_bytes_for_level_base`, so it can override if those
2009    /// parameters were set before.
2010    ///
2011    /// It sets buffer sizes so that memory consumption would be constrained by
2012    /// `memtable_memory_budget`.
2013    pub fn optimize_level_style_compaction(&mut self, memtable_memory_budget: usize) {
2014        unsafe {
2015            ffi::rocksdb_options_optimize_level_style_compaction(
2016                self.inner,
2017                memtable_memory_budget as u64,
2018            );
2019        }
2020    }
2021
2022    /// Optimize universal style compaction.
2023    ///
2024    /// Default values for some parameters in `Options` are not optimized for heavy
2025    /// workloads and big datasets, which means you might observe write stalls under
2026    /// some conditions.
2027    ///
2028    /// This can be used as one of the starting points for tuning RocksDB options in
2029    /// such cases.
2030    ///
2031    /// Internally, it sets `write_buffer_size`, `min_write_buffer_number_to_merge`,
2032    /// `max_write_buffer_number`, `level0_file_num_compaction_trigger`,
2033    /// `target_file_size_base`, `max_bytes_for_level_base`, so it can override if those
2034    /// parameters were set before.
2035    ///
2036    /// It sets buffer sizes so that memory consumption would be constrained by
2037    /// `memtable_memory_budget`.
2038    pub fn optimize_universal_style_compaction(&mut self, memtable_memory_budget: usize) {
2039        unsafe {
2040            ffi::rocksdb_options_optimize_universal_style_compaction(
2041                self.inner,
2042                memtable_memory_budget as u64,
2043            );
2044        }
2045    }
2046
2047    /// If true, the database will be created if it is missing.
2048    ///
2049    /// Default: `false`
2050    ///
2051    /// # Examples
2052    ///
2053    /// ```
2054    /// use rust_rocksdb::Options;
2055    ///
2056    /// let mut opts = Options::default();
2057    /// opts.create_if_missing(true);
2058    /// ```
2059    pub fn create_if_missing(&mut self, create_if_missing: bool) {
2060        unsafe {
2061            ffi::rocksdb_options_set_create_if_missing(
2062                self.inner,
2063                c_uchar::from(create_if_missing),
2064            );
2065        }
2066    }
2067
2068    /// If true, any column families that didn't exist when opening the database
2069    /// will be created.
2070    ///
2071    /// Default: `false`
2072    ///
2073    /// # Examples
2074    ///
2075    /// ```
2076    /// use rust_rocksdb::Options;
2077    ///
2078    /// let mut opts = Options::default();
2079    /// opts.create_missing_column_families(true);
2080    /// ```
2081    pub fn create_missing_column_families(&mut self, create_missing_cfs: bool) {
2082        unsafe {
2083            ffi::rocksdb_options_set_create_missing_column_families(
2084                self.inner,
2085                c_uchar::from(create_missing_cfs),
2086            );
2087        }
2088    }
2089
2090    /// Specifies whether an error should be raised if the database already exists.
2091    ///
2092    /// Default: false
2093    pub fn set_error_if_exists(&mut self, enabled: bool) {
2094        unsafe {
2095            ffi::rocksdb_options_set_error_if_exists(self.inner, c_uchar::from(enabled));
2096        }
2097    }
2098
2099    /// Enable/disable paranoid checks.
2100    ///
2101    /// If true, the implementation will do aggressive checking of the
2102    /// data it is processing and will stop early if it detects any
2103    /// errors. This may have unforeseen ramifications: for example, a
2104    /// corruption of one DB entry may cause a large number of entries to
2105    /// become unreadable or for the entire DB to become unopenable.
2106    /// If any of the  writes to the database fails (Put, Delete, Merge, Write),
2107    /// the database will switch to read-only mode and fail all other
2108    /// Write operations.
2109    ///
2110    /// Default: true
2111    pub fn set_paranoid_checks(&mut self, enabled: bool) {
2112        unsafe {
2113            ffi::rocksdb_options_set_paranoid_checks(self.inner, c_uchar::from(enabled));
2114        }
2115    }
2116
2117    /// A list of paths where SST files can be put into, with its target size.
2118    /// Newer data is placed into paths specified earlier in the vector while
2119    /// older data gradually moves to paths specified later in the vector.
2120    ///
2121    /// For example, you have a flash device with 10GB allocated for the DB,
2122    /// as well as a hard drive of 2TB, you should config it to be:
2123    ///   [{"/flash_path", 10GB}, {"/hard_drive", 2TB}]
2124    ///
2125    /// The system will try to guarantee data under each path is close to but
2126    /// not larger than the target size. But current and future file sizes used
2127    /// by determining where to place a file are based on best-effort estimation,
2128    /// which means there is a chance that the actual size under the directory
2129    /// is slightly more than target size under some workloads. User should give
2130    /// some buffer room for those cases.
2131    ///
2132    /// If none of the paths has sufficient room to place a file, the file will
2133    /// be placed to the last path anyway, despite to the target size.
2134    ///
2135    /// Placing newer data to earlier paths is also best-efforts. User should
2136    /// expect user files to be placed in higher levels in some extreme cases.
2137    ///
2138    /// If left empty, only one path will be used, which is `path` passed when
2139    /// opening the DB.
2140    ///
2141    /// Default: empty
2142    pub fn set_db_paths(&mut self, paths: &[DBPath]) {
2143        let mut paths: Vec<_> = paths.iter().map(|path| path.inner.cast_const()).collect();
2144        let num_paths = paths.len();
2145        unsafe {
2146            ffi::rocksdb_options_set_db_paths(self.inner, paths.as_mut_ptr(), num_paths);
2147        }
2148    }
2149
2150    /// The same list of sized paths as [`Self::set_db_paths`], but for one column family
2151    /// rather than the whole DB.
2152    ///
2153    /// When set, this wins over `db_paths` for the SST files of that column family, and
2154    /// `db_paths` keeps covering everything else. Set it on the [`Options`] you pass in the
2155    /// [`ColumnFamilyDescriptor`], not on the DB-wide options.
2156    ///
2157    /// More than one entry is only supported under level and universal compaction, and it
2158    /// forces `level_compaction_dynamic_level_bytes` off because RocksDB cannot combine the
2159    /// two. A path shared by several column families holds the files and counts the size of
2160    /// all of them against its target, so size it for the total.
2161    ///
2162    /// Default: empty, meaning the column family follows `db_paths`.
2163    pub fn set_cf_paths(&mut self, paths: &[DBPath]) {
2164        let mut paths: Vec<_> = paths.iter().map(|path| path.inner.cast_const()).collect();
2165        let num_paths = paths.len();
2166        unsafe {
2167            ffi::rocksdb_options_set_cf_paths(self.inner, paths.as_mut_ptr(), num_paths);
2168        }
2169    }
2170
2171    /// Use the specified object to interact with the environment,
2172    /// e.g. to read/write files, schedule background work, etc. In the near
2173    /// future, support for doing storage operations such as read/write files
2174    /// through env will be deprecated in favor of file_system.
2175    ///
2176    /// Default: Env::default()
2177    pub fn set_env(&mut self, env: &Env) {
2178        unsafe {
2179            ffi::rocksdb_options_set_env(self.inner, env.0.inner);
2180        }
2181        self.outlive.env = Some(env.clone());
2182    }
2183
2184    /// Sets the compression algorithm that will be used for compressing blocks.
2185    ///
2186    /// Default: `DBCompressionType::Lz4`, falling back to
2187    /// `DBCompressionType::Snappy` and then `DBCompressionType::None` when the
2188    /// preceding one is not compiled in. RocksDB 11.5.0 changed this from
2189    /// Snappy; it affects only column families that never set `compression`,
2190    /// and only newly written SST files. Existing data stays readable, since
2191    /// the decompressor is selected per block.
2192    ///
2193    /// # Examples
2194    ///
2195    /// ```
2196    /// use rust_rocksdb::{Options, DBCompressionType};
2197    ///
2198    /// let mut opts = Options::default();
2199    /// opts.set_compression_type(DBCompressionType::Snappy);
2200    /// ```
2201    pub fn set_compression_type(&mut self, t: DBCompressionType) {
2202        unsafe {
2203            ffi::rocksdb_options_set_compression(self.inner, t as c_int);
2204        }
2205    }
2206
2207    /// The compression algorithm used for new blocks.
2208    ///
2209    /// `None` covers a compression type this crate does not name: xpress, which is Windows
2210    /// only, and the custom compression range a `CompressionManager` can hand out.
2211    pub fn get_compression_type(&self) -> Option<DBCompressionType> {
2212        let raw = unsafe { ffi::rocksdb_options_get_compression(self.inner) };
2213        DBCompressionType::try_from_raw(raw)
2214    }
2215
2216    /// Number of threads for parallel compression.
2217    /// Parallel compression is enabled only if threads > 1.
2218    /// THE FEATURE IS STILL EXPERIMENTAL
2219    ///
2220    /// See [code](https://github.com/facebook/rocksdb/blob/v8.6.7/include/rocksdb/advanced_options.h#L116-L127)
2221    /// for more information.
2222    ///
2223    /// Default: 1
2224    ///
2225    /// Examples
2226    ///
2227    /// ```
2228    /// use rust_rocksdb::{Options, DBCompressionType};
2229    ///
2230    /// let mut opts = Options::default();
2231    /// opts.set_compression_type(DBCompressionType::Zstd);
2232    /// opts.set_compression_options_parallel_threads(3);
2233    /// ```
2234    pub fn set_compression_options_parallel_threads(&mut self, num: i32) {
2235        unsafe {
2236            ffi::rocksdb_options_set_compression_options_parallel_threads(self.inner, num);
2237        }
2238    }
2239
2240    /// Sets the compression algorithm that will be used for compressing WAL.
2241    ///
2242    /// At present, only ZSTD compression is supported!
2243    ///
2244    /// Default: `DBCompressionType::None`
2245    ///
2246    /// # Examples
2247    ///
2248    /// ```
2249    /// use rust_rocksdb::{Options, DBCompressionType};
2250    ///
2251    /// let mut opts = Options::default();
2252    /// opts.set_wal_compression_type(DBCompressionType::Zstd);
2253    /// // Or None to disable it
2254    /// opts.set_wal_compression_type(DBCompressionType::None);
2255    /// ```
2256    pub fn set_wal_compression_type(&mut self, t: DBCompressionType) {
2257        match t {
2258            DBCompressionType::None | DBCompressionType::Zstd => unsafe {
2259                ffi::rocksdb_options_set_wal_compression(self.inner, t as c_int);
2260            },
2261            other => unimplemented!("{:?} is not supported for WAL compression", other),
2262        }
2263    }
2264
2265    /// The compression algorithm used for the WAL, `DBCompressionType::None` when disabled.
2266    ///
2267    /// `None` covers a compression type this crate does not name. Only ZSTD can reach here
2268    /// through [`Self::set_wal_compression_type`], but an options string can set anything.
2269    pub fn get_wal_compression_type(&self) -> Option<DBCompressionType> {
2270        let raw = unsafe { ffi::rocksdb_options_get_wal_compression(self.inner) };
2271        DBCompressionType::try_from_raw(raw)
2272    }
2273
2274    /// Sets the bottom-most compression algorithm that will be used for
2275    /// compressing blocks at the bottom-most level.
2276    ///
2277    /// Note that to actually enable bottom-most compression configuration after
2278    /// setting the compression type, it needs to be enabled by calling
2279    /// [`set_bottommost_compression_options`](#method.set_bottommost_compression_options) or
2280    /// [`set_bottommost_zstd_max_train_bytes`](#method.set_bottommost_zstd_max_train_bytes) method with `enabled` argument
2281    /// set to `true`.
2282    ///
2283    /// # Examples
2284    ///
2285    /// ```
2286    /// use rust_rocksdb::{Options, DBCompressionType};
2287    ///
2288    /// let mut opts = Options::default();
2289    /// opts.set_bottommost_compression_type(DBCompressionType::Zstd);
2290    /// opts.set_bottommost_zstd_max_train_bytes(0, true);
2291    /// ```
2292    pub fn set_bottommost_compression_type(&mut self, t: DBCompressionType) {
2293        unsafe {
2294            ffi::rocksdb_options_set_bottommost_compression(self.inner, t as c_int);
2295        }
2296    }
2297
2298    /// The compression algorithm set for the bottom-most level.
2299    ///
2300    /// The default is the `kDisableCompressionOption` sentinel, which this crate does not
2301    /// name, so an untouched `Options` reads back as `None`. That sentinel means the
2302    /// bottom-most level follows [`Self::set_compression_type`] like every other level.
2303    pub fn get_bottommost_compression_type(&self) -> Option<DBCompressionType> {
2304        let raw = unsafe { ffi::rocksdb_options_get_bottommost_compression(self.inner) };
2305        DBCompressionType::try_from_raw(raw)
2306    }
2307
2308    /// Different levels can have different compression policies. There
2309    /// are cases where most lower levels would like to use quick compression
2310    /// algorithms while the higher levels (which have more data) use
2311    /// compression algorithms that have better compression but could
2312    /// be slower. This array, if non-empty, should have an entry for
2313    /// each level of the database; these override the value specified in
2314    /// the previous field 'compression'.
2315    ///
2316    /// # Examples
2317    ///
2318    /// ```
2319    /// use rust_rocksdb::{Options, DBCompressionType};
2320    ///
2321    /// let mut opts = Options::default();
2322    /// opts.set_compression_per_level(&[
2323    ///     DBCompressionType::None,
2324    ///     DBCompressionType::None,
2325    ///     DBCompressionType::Snappy,
2326    ///     DBCompressionType::Snappy,
2327    ///     DBCompressionType::Snappy
2328    /// ]);
2329    /// ```
2330    pub fn set_compression_per_level(&mut self, level_types: &[DBCompressionType]) {
2331        unsafe {
2332            let mut level_types: Vec<_> = level_types.iter().map(|&t| t as c_int).collect();
2333            ffi::rocksdb_options_set_compression_per_level(
2334                self.inner,
2335                level_types.as_mut_ptr(),
2336                level_types.len() as size_t,
2337            );
2338        }
2339    }
2340
2341    /// Maximum size of dictionaries used to prime the compression library.
2342    /// Enabling dictionary can improve compression ratios when there are
2343    /// repetitions across data blocks.
2344    ///
2345    /// The dictionary is created by sampling the SST file data. If
2346    /// `zstd_max_train_bytes` is nonzero, the samples are passed through zstd's
2347    /// dictionary generator. Otherwise, the random samples are used directly as
2348    /// the dictionary.
2349    ///
2350    /// When compression dictionary is disabled, we compress and write each block
2351    /// before buffering data for the next one. When compression dictionary is
2352    /// enabled, we buffer all SST file data in-memory so we can sample it, as data
2353    /// can only be compressed and written after the dictionary has been finalized.
2354    /// So users of this feature may see increased memory usage.
2355    ///
2356    /// Default: `0`
2357    ///
2358    /// # Examples
2359    ///
2360    /// ```
2361    /// use rust_rocksdb::Options;
2362    ///
2363    /// let mut opts = Options::default();
2364    /// opts.set_compression_options(4, 5, 6, 7);
2365    /// ```
2366    pub fn set_compression_options(
2367        &mut self,
2368        w_bits: c_int,
2369        level: c_int,
2370        strategy: c_int,
2371        max_dict_bytes: c_int,
2372    ) {
2373        unsafe {
2374            ffi::rocksdb_options_set_compression_options(
2375                self.inner,
2376                w_bits,
2377                level,
2378                strategy,
2379                max_dict_bytes,
2380            );
2381        }
2382    }
2383
2384    /// Sets compression options for blocks at the bottom-most level.  Meaning
2385    /// of all settings is the same as in [`set_compression_options`](#method.set_compression_options) method but
2386    /// affect only the bottom-most compression which is set using
2387    /// [`set_bottommost_compression_type`](#method.set_bottommost_compression_type) method.
2388    ///
2389    /// # Examples
2390    ///
2391    /// ```
2392    /// use rust_rocksdb::{Options, DBCompressionType};
2393    ///
2394    /// let mut opts = Options::default();
2395    /// opts.set_bottommost_compression_type(DBCompressionType::Zstd);
2396    /// opts.set_bottommost_compression_options(4, 5, 6, 7, true);
2397    /// ```
2398    pub fn set_bottommost_compression_options(
2399        &mut self,
2400        w_bits: c_int,
2401        level: c_int,
2402        strategy: c_int,
2403        max_dict_bytes: c_int,
2404        enabled: bool,
2405    ) {
2406        unsafe {
2407            ffi::rocksdb_options_set_bottommost_compression_options(
2408                self.inner,
2409                w_bits,
2410                level,
2411                strategy,
2412                max_dict_bytes,
2413                c_uchar::from(enabled),
2414            );
2415        }
2416    }
2417
2418    /// Sets maximum size of training data passed to zstd's dictionary trainer. Using zstd's
2419    /// dictionary trainer can achieve even better compression ratio improvements than using
2420    /// `max_dict_bytes` alone.
2421    ///
2422    /// The training data will be used to generate a dictionary of max_dict_bytes.
2423    ///
2424    /// Default: 0.
2425    pub fn set_zstd_max_train_bytes(&mut self, value: c_int) {
2426        unsafe {
2427            ffi::rocksdb_options_set_compression_options_zstd_max_train_bytes(self.inner, value);
2428        }
2429    }
2430
2431    /// Sets maximum size of training data passed to zstd's dictionary trainer
2432    /// when compressing the bottom-most level. Using zstd's dictionary trainer
2433    /// can achieve even better compression ratio improvements than using
2434    /// `max_dict_bytes` alone.
2435    ///
2436    /// The training data will be used to generate a dictionary of
2437    /// `max_dict_bytes`.
2438    ///
2439    /// Default: 0.
2440    pub fn set_bottommost_zstd_max_train_bytes(&mut self, value: c_int, enabled: bool) {
2441        unsafe {
2442            ffi::rocksdb_options_set_bottommost_compression_options_zstd_max_train_bytes(
2443                self.inner,
2444                value,
2445                c_uchar::from(enabled),
2446            );
2447        }
2448    }
2449
2450    /// If non-zero, we perform bigger reads when doing compaction. If you're
2451    /// running RocksDB on spinning disks, you should set this to at least 2MB.
2452    /// That way RocksDB's compaction is doing sequential instead of random reads.
2453    ///
2454    /// Default: 2 * 1024 * 1024 (2 MB)
2455    pub fn set_compaction_readahead_size(&mut self, compaction_readahead_size: usize) {
2456        unsafe {
2457            ffi::rocksdb_options_compaction_readahead_size(self.inner, compaction_readahead_size);
2458        }
2459    }
2460
2461    /// Allow RocksDB to pick dynamic base of bytes for levels.
2462    /// With this feature turned on, RocksDB will automatically adjust max bytes for each level.
2463    /// The goal of this feature is to have lower bound on size amplification.
2464    ///
2465    /// Default: true.
2466    pub fn set_level_compaction_dynamic_level_bytes(&mut self, v: bool) {
2467        unsafe {
2468            ffi::rocksdb_options_set_level_compaction_dynamic_level_bytes(
2469                self.inner,
2470                c_uchar::from(v),
2471            );
2472        }
2473    }
2474
2475    /// This option has different meanings for different compaction styles:
2476    ///
2477    /// Leveled: files older than `periodic_compaction_seconds` will be picked up
2478    /// for compaction and will be re-written to the same level as they were
2479    /// before if level_compaction_dynamic_level_bytes is disabled. Otherwise,
2480    /// it will rewrite files to the next level except for the last level files
2481    /// to the same level.
2482    ///
2483    /// FIFO: not supported. Setting this option has no effect for FIFO compaction.
2484    ///
2485    /// Universal: when there are files older than `periodic_compaction_seconds`,
2486    /// rocksdb will try to do as large a compaction as possible including the
2487    /// last level. Such compaction is only skipped if only last level is to
2488    /// be compacted and no file in last level is older than
2489    /// `periodic_compaction_seconds`. See more in
2490    /// UniversalCompactionBuilder::PickPeriodicCompaction().
2491    /// For backward compatibility, the effective value of this option takes
2492    /// into account the value of option `ttl`. The logic is as follows:
2493    ///
2494    /// - both options are set to 30 days if they have the default value.
2495    /// - if both options are zero, zero is picked. Otherwise, we take the min
2496    ///   value among non-zero options values (i.e. takes the stricter limit).
2497    ///
2498    /// One main use of the feature is to make sure a file goes through compaction
2499    /// filters periodically. Users can also use the feature to clear up SST
2500    /// files using old format.
2501    ///
2502    /// A file's age is computed by looking at file_creation_time or creation_time
2503    /// table properties in order, if they have valid non-zero values; if not, the
2504    /// age is based on the file's last modified time (given by the underlying
2505    /// Env).
2506    ///
2507    /// This option only supports block based table format for any compaction
2508    /// style.
2509    ///
2510    /// unit: seconds. Ex: 7 days = 7 * 24 * 60 * 60
2511    ///
2512    /// Values:
2513    /// 0: Turn off Periodic compactions.
2514    /// UINT64_MAX - 1 (0xfffffffffffffffe) is special flag to allow RocksDB to
2515    /// pick default.
2516    ///
2517    /// Default: 30 days if using block based table format + compaction filter +
2518    /// leveled compaction or block based table format + universal compaction.
2519    /// 0 (disabled) otherwise.
2520    ///
2521    pub fn set_periodic_compaction_seconds(&mut self, secs: u64) {
2522        unsafe {
2523            ffi::rocksdb_options_set_periodic_compaction_seconds(self.inner, secs);
2524        }
2525    }
2526
2527    /// When an iterator scans this number of invisible entries (tombstones or
2528    /// hidden puts) from the active memtable during a single iterator operation,
2529    /// we will attempt to flush the memtable. Currently only forward scans are
2530    /// supported (SeekToFirst(), Seek() and Next()).
2531    /// This option helps to reduce the overhead of scanning through a
2532    /// large number of entries in memtable.
2533    /// Users should consider enable deletion-triggered-compaction (see
2534    /// CompactOnDeletionCollectorFactory) together with this option to compact
2535    /// away tombstones after the memtable is flushed.
2536    ///
2537    /// Default: 0 (disabled)
2538    /// Dynamically changeable through the SetOptions() API.
2539    pub fn set_memtable_op_scan_flush_trigger(&mut self, num: u32) {
2540        unsafe {
2541            ffi::rocksdb_options_set_memtable_op_scan_flush_trigger(self.inner, num);
2542        }
2543    }
2544
2545    /// Similar to `memtable_op_scan_flush_trigger`, but this option applies to
2546    /// Next() calls between Seeks or until iterator destruction. If the average
2547    /// of the number of invisible entries scanned from the active memtable, the
2548    /// memtable will be marked for flush.
2549    /// Note that to avoid the case where the window between Seeks is too small,
2550    /// the option only takes effect if the total number of hidden entries scanned
2551    /// within a window is at least `memtable_op_scan_flush_trigger`. So this
2552    /// option is only effective when `memtable_op_scan_flush_trigger` is set.
2553    ///
2554    /// This option should be set to a lower value than
2555    /// `memtable_op_scan_flush_trigger`. It covers the case where an iterator
2556    /// scans through an expensive key range with many invisible entries from the
2557    /// active memtable, but the number of invisible entries per operation does not
2558    /// exceed `memtable_op_scan_flush_trigger`.
2559    ///
2560    /// Default: 0 (disabled)
2561    /// Dynamically changeable through the SetOptions() API.
2562    pub fn set_memtable_avg_op_scan_flush_trigger(&mut self, num: u32) {
2563        unsafe {
2564            ffi::rocksdb_options_set_memtable_avg_op_scan_flush_trigger(self.inner, num);
2565        }
2566    }
2567
2568    /// This option has different meanings for different compaction styles:
2569    ///
2570    /// Leveled: Non-bottom-level files with all keys older than TTL will go
2571    ///    through the compaction process. This usually happens in a cascading
2572    ///    way so that those entries will be compacted to bottommost level/file.
2573    ///    The feature is used to remove stale entries that have been deleted or
2574    ///    updated from the file system.
2575    ///
2576    /// FIFO: Files with all keys older than TTL will be deleted. TTL is only
2577    ///    supported if option max_open_files is set to -1.
2578    ///
2579    /// Universal: users should only set the option `periodic_compaction_seconds`
2580    ///    instead. For backward compatibility, this option has the same
2581    ///    meaning as `periodic_compaction_seconds`. See more in comments for
2582    ///    `periodic_compaction_seconds` on the interaction between these two
2583    ///    options.
2584    ///
2585    /// This option only supports block based table format for any compaction
2586    /// style.
2587    ///
2588    /// unit: seconds. Ex: 1 day = 1 * 24 * 60 * 60
2589    /// 0 means disabling.
2590    /// UINT64_MAX - 1 (0xfffffffffffffffe) is special flag to allow RocksDB to
2591    /// pick default.
2592    ///
2593    /// Default: 30 days if using block based table. 0 (disable) otherwise.
2594    ///
2595    /// Dynamically changeable
2596    /// Note that dynamically changing this option only works for leveled and FIFO
2597    /// compaction. For universal compaction, dynamically changing this option has
2598    /// no effect, users should dynamically change `periodic_compaction_seconds`
2599    /// instead.
2600    pub fn set_ttl(&mut self, secs: u64) {
2601        unsafe {
2602            ffi::rocksdb_options_set_ttl(self.inner, secs);
2603        }
2604    }
2605
2606    pub fn set_merge_operator_associative<F: MergeFn + Clone>(
2607        &mut self,
2608        name: impl CStrLike,
2609        full_merge_fn: F,
2610    ) {
2611        let cb = Box::new(MergeOperatorCallback {
2612            name: name.into_c_string().unwrap(),
2613            full_merge_fn: full_merge_fn.clone(),
2614            partial_merge_fn: full_merge_fn,
2615        });
2616
2617        unsafe {
2618            let mo = ffi::rocksdb_mergeoperator_create(
2619                Box::into_raw(cb).cast::<c_void>(),
2620                Some(merge_operator::destructor_callback::<F, F>),
2621                Some(full_merge_callback::<F, F>),
2622                Some(partial_merge_callback::<F, F>),
2623                Some(merge_operator::delete_callback),
2624                Some(merge_operator::name_callback::<F, F>),
2625            );
2626            ffi::rocksdb_options_set_merge_operator(self.inner, mo);
2627        }
2628    }
2629
2630    pub fn set_merge_operator<F: MergeFn, PF: MergeFn>(
2631        &mut self,
2632        name: impl CStrLike,
2633        full_merge_fn: F,
2634        partial_merge_fn: PF,
2635    ) {
2636        let cb = Box::new(MergeOperatorCallback {
2637            name: name.into_c_string().unwrap(),
2638            full_merge_fn,
2639            partial_merge_fn,
2640        });
2641
2642        unsafe {
2643            let mo = ffi::rocksdb_mergeoperator_create(
2644                Box::into_raw(cb).cast::<c_void>(),
2645                Some(merge_operator::destructor_callback::<F, PF>),
2646                Some(full_merge_callback::<F, PF>),
2647                Some(partial_merge_callback::<F, PF>),
2648                Some(merge_operator::delete_callback),
2649                Some(merge_operator::name_callback::<F, PF>),
2650            );
2651            ffi::rocksdb_options_set_merge_operator(self.inner, mo);
2652        }
2653    }
2654
2655    #[deprecated(
2656        since = "0.5.0",
2657        note = "add_merge_operator has been renamed to set_merge_operator"
2658    )]
2659    pub fn add_merge_operator<F: MergeFn + Clone>(&mut self, name: &str, merge_fn: F) {
2660        self.set_merge_operator_associative(name, merge_fn);
2661    }
2662
2663    /// Sets a compaction filter used to determine if entries should be kept, changed,
2664    /// or removed during compaction.
2665    ///
2666    /// An example use case is to remove entries with an expired TTL.
2667    ///
2668    /// If you take a snapshot of the database, only values written since the last
2669    /// snapshot will be passed through the compaction filter.
2670    ///
2671    /// If multi-threaded compaction is used, `filter_fn` may be called multiple times
2672    /// simultaneously.
2673    pub fn set_compaction_filter<F>(&mut self, name: impl CStrLike, filter_fn: F)
2674    where
2675        F: CompactionFilterFn + Send + 'static,
2676    {
2677        let cb = Box::new(CompactionFilterCallback {
2678            name: name.into_c_string().unwrap(),
2679            filter_fn,
2680        });
2681
2682        let filter = unsafe {
2683            let cf = ffi::rocksdb_compactionfilter_create(
2684                Box::into_raw(cb).cast::<c_void>(),
2685                Some(compaction_filter::destructor_callback::<CompactionFilterCallback<F>>),
2686                Some(compaction_filter::filter_callback::<CompactionFilterCallback<F>>),
2687                Some(compaction_filter::name_callback::<CompactionFilterCallback<F>>),
2688            );
2689            ffi::rocksdb_options_set_compaction_filter(self.inner, cf);
2690
2691            OwnedCompactionFilter::new(NonNull::new(cf).unwrap())
2692        };
2693        self.outlive.compaction_filter = Some(Arc::new(filter));
2694    }
2695
2696    pub fn add_event_listener<L: EventListener>(&mut self, l: L) {
2697        let handle = new_event_listener(l);
2698        unsafe { ffi::rust_rocksdb_options_add_eventlistener(self.inner, handle.inner) }
2699    }
2700
2701    /// This is a factory that provides compaction filter objects which allow
2702    /// an application to modify/delete a key-value during background compaction.
2703    ///
2704    /// A new filter will be created on each compaction run.  If multithreaded
2705    /// compaction is being used, each created CompactionFilter will only be used
2706    /// from a single thread and so does not need to be thread-safe.
2707    ///
2708    /// Default: nullptr
2709    pub fn set_compaction_filter_factory<F>(&mut self, factory: F)
2710    where
2711        F: CompactionFilterFactory + 'static,
2712    {
2713        let factory = Box::new(factory);
2714
2715        unsafe {
2716            let cff = ffi::rocksdb_compactionfilterfactory_create(
2717                Box::into_raw(factory).cast::<c_void>(),
2718                Some(compaction_filter_factory::destructor_callback::<F>),
2719                Some(compaction_filter_factory::create_compaction_filter_callback::<F>),
2720                Some(compaction_filter_factory::name_callback::<F>),
2721            );
2722
2723            ffi::rocksdb_options_set_compaction_filter_factory(self.inner, cff);
2724        }
2725    }
2726
2727    /// Makes compaction cut its output files on the boundaries this factory
2728    /// reports, so a key prefix stays inside a single SST.
2729    ///
2730    /// See the [`sst_partitioner`](crate::sst_partitioner) module for what that
2731    /// buys and what it does not. Only files written by later compactions are
2732    /// partitioned, so setting this on an existing DB takes effect gradually.
2733    ///
2734    /// Marked experimental upstream. Default: no partitioner.
2735    ///
2736    /// # Examples
2737    ///
2738    /// ```
2739    /// use rust_rocksdb::{Options, SstPartitionerFactory};
2740    ///
2741    /// let mut opts = Options::default();
2742    /// opts.set_sst_partitioner_factory(&SstPartitionerFactory::fixed_prefix(8));
2743    /// ```
2744    pub fn set_sst_partitioner_factory(&mut self, factory: &SstPartitionerFactory) {
2745        // `rocksdb_options_set_sst_partitioner_factory` assigns `factory->rep`
2746        // into `Options::sst_partitioner_factory` (c.cc:6142), copying the
2747        // `shared_ptr`. The options object holds its own reference from here
2748        // on, so the caller's handle is free to drop at any time.
2749        unsafe {
2750            ffi::rocksdb_options_set_sst_partitioner_factory(self.inner, factory.as_ptr());
2751        }
2752    }
2753
2754    /// Makes RocksDB compute a checksum over each SST file it writes and record
2755    /// it in the manifest.
2756    ///
2757    /// Nothing verifies file checksums until this is set, and files already on
2758    /// disk stay without one until a compaction rewrites them. See the
2759    /// [`file_checksum`](crate::file_checksum) module for how this differs from
2760    /// the per-block checksum on [`BlockBasedOptions::set_checksum_type`].
2761    ///
2762    /// Default: none, so no file checksums are produced or checked.
2763    ///
2764    /// # Examples
2765    ///
2766    /// ```
2767    /// use rust_rocksdb::{FileChecksumGenFactory, Options};
2768    ///
2769    /// let mut opts = Options::default();
2770    /// opts.set_file_checksum_gen_factory(&FileChecksumGenFactory::crc32c());
2771    /// ```
2772    pub fn set_file_checksum_gen_factory(&mut self, factory: &FileChecksumGenFactory) {
2773        // `rocksdb_options_set_file_checksum_gen_factory` assigns
2774        // `factory->rep` into `Options::file_checksum_gen_factory` (c.cc:6067),
2775        // copying the `shared_ptr`. The options object holds its own reference
2776        // from here on, so the caller's handle is free to drop at any time.
2777        unsafe {
2778            ffi::rocksdb_options_set_file_checksum_gen_factory(self.inner, factory.as_ptr());
2779        }
2780    }
2781
2782    /// Sends this DB's compactions to `service` instead of running them
2783    /// locally.
2784    ///
2785    /// RocksDB serializes each compaction, hands it to
2786    /// [`schedule`](CompactionService::schedule), and blocks in
2787    /// [`wait`](CompactionService::wait) until the worker returns a result. See
2788    /// the [`compaction_service`](crate::compaction_service) module for the
2789    /// worker half and for the panic and threading rules the service methods
2790    /// run under.
2791    ///
2792    /// Upstream marks this experimental and reserves the right to change it
2793    /// without compatibility guarantees.
2794    ///
2795    /// Replaces any service set earlier. Default: none.
2796    pub fn set_compaction_service<S>(&mut self, service: S)
2797    where
2798        S: CompactionService + 'static,
2799    {
2800        // `rocksdb_options_set_compaction_service` adopts the pointer into a
2801        // fresh `std::shared_ptr<CompactionService>` (c.cc:1361), so RocksDB
2802        // owns the service and the boxed implementation behind it from here on.
2803        // Nothing goes in `OptionsMustOutliveDB`: cloning the options copies
2804        // the `shared_ptr`, and the last copy to drop frees the service.
2805        unsafe {
2806            ffi::rocksdb_options_set_compaction_service(
2807                self.inner,
2808                new_compaction_service(service).into_ptr(),
2809            );
2810        }
2811    }
2812
2813    /// Installs a filter that sees every WAL record replayed during recovery
2814    /// and decides what to do with it.
2815    ///
2816    /// The filter runs inside [`DB::open`](crate::DB::open) and is never
2817    /// consulted again once the DB is up. See the
2818    /// [`wal_filter`](crate::wal_filter) module for the decisions it can make
2819    /// and for the panic and threading rules its methods run under.
2820    ///
2821    /// This is a DB-wide option. Setting it on a column family's `Options` has
2822    /// no effect.
2823    ///
2824    /// Replaces any filter set earlier. Default: none.
2825    pub fn set_wal_filter<F>(&mut self, filter: F)
2826    where
2827        F: WalFilter + 'static,
2828    {
2829        // `rocksdb_options_set_wal_filter` stores the bare pointer in
2830        // `DBOptions::wal_filter` (c.cc:5843). RocksDB never copies or frees
2831        // it, so the filter has to outlive the options and every DB opened
2832        // from them, which is what `OptionsMustOutliveDB` is for.
2833        let handle = new_wal_filter(filter);
2834        unsafe {
2835            ffi::rocksdb_options_set_wal_filter(self.inner, handle.as_ptr());
2836        }
2837        self.outlive.wal_filter = Some(Arc::new(handle));
2838    }
2839
2840    /// Removes the filter set by [`Self::set_wal_filter`], so recovery replays
2841    /// every WAL record as written.
2842    ///
2843    /// This only clears these `Options`. A DB already opened from them keeps
2844    /// the filter it was opened with, and so does any `Options` cloned before
2845    /// this call.
2846    pub fn clear_wal_filter(&mut self) {
2847        unsafe {
2848            ffi::rocksdb_options_clear_wal_filter(self.inner);
2849        }
2850        self.outlive.wal_filter = None;
2851    }
2852
2853    /// Sets the comparator used to define the order of keys in the table.
2854    /// Default: a comparator that uses lexicographic byte-wise ordering
2855    ///
2856    /// The client must ensure that the comparator supplied here has the same
2857    /// name and orders keys *exactly* the same as the comparator provided to
2858    /// previous open calls on the same DB.
2859    pub fn set_comparator(&mut self, name: impl CStrLike, compare_fn: Box<CompareFn>) {
2860        let cb = Box::new(ComparatorCallback {
2861            name: name.into_c_string().unwrap(),
2862            compare_fn,
2863        });
2864
2865        let cmp = unsafe {
2866            let cmp = ffi::rocksdb_comparator_create(
2867                Box::into_raw(cb).cast::<c_void>(),
2868                Some(ComparatorCallback::destructor_callback),
2869                Some(ComparatorCallback::compare_callback),
2870                Some(ComparatorCallback::name_callback),
2871            );
2872            ffi::rocksdb_options_set_comparator(self.inner, cmp);
2873            Comparator::from_raw(NonNull::new(cmp).unwrap())
2874        };
2875        self.outlive.comparator = Some(Arc::new(cmp));
2876    }
2877
2878    /// Sets the comparator that are timestamp-aware, used to define the order of keys in the table,
2879    /// taking timestamp into consideration.
2880    /// Find more information on timestamp-aware comparator on [here](https://github.com/facebook/rocksdb/wiki/User-defined-Timestamp)
2881    ///
2882    /// The client must ensure that the comparator supplied here has the same
2883    /// name and orders keys *exactly* the same as the comparator provided to
2884    /// previous open calls on the same DB.
2885    pub fn set_comparator_with_ts(
2886        &mut self,
2887        name: impl CStrLike,
2888        timestamp_size: usize,
2889        compare_fn: Box<CompareFn>,
2890        compare_ts_fn: Box<CompareTsFn>,
2891        compare_without_ts_fn: Box<CompareWithoutTsFn>,
2892    ) {
2893        let cb = Box::new(ComparatorWithTsCallback {
2894            name: name.into_c_string().unwrap(),
2895            compare_fn,
2896            compare_ts_fn,
2897            compare_without_ts_fn,
2898        });
2899
2900        let cmp = unsafe {
2901            let cmp = ffi::rocksdb_comparator_with_ts_create(
2902                Box::into_raw(cb).cast::<c_void>(),
2903                Some(ComparatorWithTsCallback::destructor_callback),
2904                Some(ComparatorWithTsCallback::compare_callback),
2905                Some(ComparatorWithTsCallback::compare_ts_callback),
2906                Some(ComparatorWithTsCallback::compare_without_ts_callback),
2907                Some(ComparatorWithTsCallback::name_callback),
2908                timestamp_size,
2909            );
2910            ffi::rocksdb_options_set_comparator(self.inner, cmp);
2911            Comparator::from_raw(NonNull::new(cmp).unwrap())
2912        };
2913        self.outlive.comparator = Some(Arc::new(cmp));
2914    }
2915
2916    pub fn set_prefix_extractor(&mut self, prefix_extractor: SliceTransform) {
2917        unsafe {
2918            ffi::rocksdb_options_set_prefix_extractor(self.inner, prefix_extractor.inner);
2919        }
2920    }
2921
2922    // Use this if you don't need to keep the data sorted, i.e. you'll never use
2923    // an iterator, only Put() and Get() API calls
2924    //
2925    pub fn optimize_for_point_lookup(&mut self, block_cache_size_mb: u64) {
2926        unsafe {
2927            ffi::rocksdb_options_optimize_for_point_lookup(self.inner, block_cache_size_mb);
2928        }
2929    }
2930
2931    /// Sets the optimize_filters_for_hits flag
2932    ///
2933    /// Default: `false`
2934    ///
2935    /// # Examples
2936    ///
2937    /// ```
2938    /// use rust_rocksdb::Options;
2939    ///
2940    /// let mut opts = Options::default();
2941    /// opts.set_optimize_filters_for_hits(true);
2942    /// ```
2943    pub fn set_optimize_filters_for_hits(&mut self, optimize_for_hits: bool) {
2944        unsafe {
2945            ffi::rocksdb_options_set_optimize_filters_for_hits(
2946                self.inner,
2947                c_int::from(optimize_for_hits),
2948            );
2949        }
2950    }
2951
2952    /// Sets the periodicity when obsolete files get deleted.
2953    ///
2954    /// The files that get out of scope by compaction
2955    /// process will still get automatically delete on every compaction,
2956    /// regardless of this setting.
2957    ///
2958    /// Default: 6 hours
2959    pub fn set_delete_obsolete_files_period_micros(&mut self, micros: u64) {
2960        unsafe {
2961            ffi::rocksdb_options_set_delete_obsolete_files_period_micros(self.inner, micros);
2962        }
2963    }
2964
2965    /// Prepare the DB for bulk loading.
2966    ///
2967    /// All data will be in level 0 without any automatic compaction.
2968    /// It's recommended to manually call CompactRange(NULL, NULL) before reading
2969    /// from the database, because otherwise the read can be very slow.
2970    pub fn prepare_for_bulk_load(&mut self) {
2971        unsafe {
2972            ffi::rocksdb_options_prepare_for_bulk_load(self.inner);
2973        }
2974    }
2975
2976    /// Sets the number of open files that can be used by the DB. You may need to
2977    /// increase this if your database has a large working set. Value `-1` means
2978    /// files opened are always kept open. You can estimate number of files based
2979    /// on target_file_size_base and target_file_size_multiplier for level-based
2980    /// compaction. For universal-style compaction, you can usually set it to `-1`.
2981    ///
2982    /// Default: `-1`
2983    ///
2984    /// # Examples
2985    ///
2986    /// ```
2987    /// use rust_rocksdb::Options;
2988    ///
2989    /// let mut opts = Options::default();
2990    /// opts.set_max_open_files(10);
2991    /// ```
2992    pub fn set_max_open_files(&mut self, nfiles: c_int) {
2993        unsafe {
2994            ffi::rocksdb_options_set_max_open_files(self.inner, nfiles);
2995        }
2996    }
2997
2998    /// If max_open_files is -1, DB will open all files on DB::Open(). You can
2999    /// use this option to increase the number of threads used to open the files.
3000    /// Default: 16
3001    pub fn set_max_file_opening_threads(&mut self, nthreads: c_int) {
3002        unsafe {
3003            ffi::rocksdb_options_set_max_file_opening_threads(self.inner, nthreads);
3004        }
3005    }
3006
3007    /// By default, writes to stable storage use fdatasync (on platforms
3008    /// where this function is available). If this option is true,
3009    /// fsync is used instead.
3010    ///
3011    /// fsync and fdatasync are equally safe for our purposes and fdatasync is
3012    /// faster, so it is rarely necessary to set this option. It is provided
3013    /// as a workaround for kernel/filesystem bugs, such as one that affected
3014    /// fdatasync with ext4 in kernel versions prior to 3.7.
3015    ///
3016    /// Default: `false`
3017    ///
3018    /// # Examples
3019    ///
3020    /// ```
3021    /// use rust_rocksdb::Options;
3022    ///
3023    /// let mut opts = Options::default();
3024    /// opts.set_use_fsync(true);
3025    /// ```
3026    pub fn set_use_fsync(&mut self, useit: bool) {
3027        unsafe {
3028            ffi::rocksdb_options_set_use_fsync(self.inner, c_int::from(useit));
3029        }
3030    }
3031
3032    /// Returns the value of the `use_fsync` option.
3033    pub fn get_use_fsync(&self) -> bool {
3034        let val = unsafe { ffi::rocksdb_options_get_use_fsync(self.inner) };
3035        val != 0
3036    }
3037
3038    /// Specifies the absolute info LOG dir.
3039    ///
3040    /// If it is empty, the log files will be in the same dir as data.
3041    /// If it is non empty, the log files will be in the specified dir,
3042    /// and the db data dir's absolute path will be used as the log file
3043    /// name's prefix.
3044    ///
3045    /// Default: empty
3046    pub fn set_db_log_dir<P: AsRef<Path>>(&mut self, path: P) {
3047        let p = to_cpath(path).unwrap();
3048        unsafe {
3049            ffi::rocksdb_options_set_db_log_dir(self.inner, p.as_ptr());
3050        }
3051    }
3052
3053    /// The info LOG dir set by [`Self::set_db_log_dir`], empty when logs go next to the data.
3054    pub fn get_db_log_dir(&self) -> String {
3055        let mut len: size_t = 0;
3056        let path = unsafe { ffi::rocksdb_options_get_db_log_dir(self.inner, &raw mut len) };
3057        unsafe { borrowed_string(path, len) }
3058    }
3059
3060    /// Specifies the log level.
3061    /// Consider the `LogLevel` enum for a list of possible levels.
3062    ///
3063    /// Default: Info
3064    ///
3065    /// # Examples
3066    ///
3067    /// ```
3068    /// use rust_rocksdb::{Options, LogLevel};
3069    ///
3070    /// let mut opts = Options::default();
3071    /// opts.set_log_level(LogLevel::Warn);
3072    /// ```
3073    pub fn set_log_level(&mut self, level: LogLevel) {
3074        unsafe {
3075            ffi::rocksdb_options_set_info_log_level(self.inner, level as c_int);
3076        }
3077    }
3078
3079    /// The verbosity set by [`Self::set_log_level`].
3080    ///
3081    /// `None` covers a level this crate does not name, which today only means RocksDB's
3082    /// `NUM_INFO_LOG_LEVELS` sentinel.
3083    pub fn get_log_level(&self) -> Option<LogLevel> {
3084        let raw = unsafe { ffi::rocksdb_options_get_info_log_level(self.inner) };
3085        LogLevel::try_from_raw(raw)
3086    }
3087
3088    /// Allows OS to incrementally sync files to disk while they are being
3089    /// written, asynchronously, in the background. This operation can be used
3090    /// to smooth out write I/Os over time. Users shouldn't rely on it for
3091    /// persistency guarantee.
3092    /// Issue one request for every bytes_per_sync written. `0` turns it off.
3093    ///
3094    /// Default: `0`
3095    ///
3096    /// You may consider using rate_limiter to regulate write rate to device.
3097    /// When rate limiter is enabled, it automatically enables bytes_per_sync
3098    /// to 1MB.
3099    ///
3100    /// This option applies to table files
3101    ///
3102    /// # Examples
3103    ///
3104    /// ```
3105    /// use rust_rocksdb::Options;
3106    ///
3107    /// let mut opts = Options::default();
3108    /// opts.set_bytes_per_sync(1024 * 1024);
3109    /// ```
3110    pub fn set_bytes_per_sync(&mut self, nbytes: u64) {
3111        unsafe {
3112            ffi::rocksdb_options_set_bytes_per_sync(self.inner, nbytes);
3113        }
3114    }
3115
3116    /// Same as bytes_per_sync, but applies to WAL files.
3117    ///
3118    /// Default: 0, turned off
3119    ///
3120    /// Dynamically changeable through SetDBOptions() API.
3121    pub fn set_wal_bytes_per_sync(&mut self, nbytes: u64) {
3122        unsafe {
3123            ffi::rocksdb_options_set_wal_bytes_per_sync(self.inner, nbytes);
3124        }
3125    }
3126
3127    /// Sets the maximum buffer size that is used by WritableFileWriter.
3128    ///
3129    /// On Windows, we need to maintain an aligned buffer for writes.
3130    /// We allow the buffer to grow until it's size hits the limit in buffered
3131    /// IO and fix the buffer size when using direct IO to ensure alignment of
3132    /// write requests if the logical sector size is unusual
3133    ///
3134    /// Default: 1024 * 1024 (1 MB)
3135    ///
3136    /// Dynamically changeable through SetDBOptions() API.
3137    pub fn set_writable_file_max_buffer_size(&mut self, nbytes: u64) {
3138        unsafe {
3139            ffi::rocksdb_options_set_writable_file_max_buffer_size(self.inner, nbytes);
3140        }
3141    }
3142
3143    /// If true, allow multi-writers to update mem tables in parallel.
3144    /// Only some memtable_factory-s support concurrent writes; currently it
3145    /// is implemented only for SkipListFactory.  Concurrent memtable writes
3146    /// are not compatible with inplace_update_support or filter_deletes.
3147    /// It is strongly recommended to set enable_write_thread_adaptive_yield
3148    /// if you are going to use this feature.
3149    ///
3150    /// Default: true
3151    ///
3152    /// # Examples
3153    ///
3154    /// ```
3155    /// use rust_rocksdb::Options;
3156    ///
3157    /// let mut opts = Options::default();
3158    /// opts.set_allow_concurrent_memtable_write(false);
3159    /// ```
3160    pub fn set_allow_concurrent_memtable_write(&mut self, allow: bool) {
3161        unsafe {
3162            ffi::rocksdb_options_set_allow_concurrent_memtable_write(
3163                self.inner,
3164                c_uchar::from(allow),
3165            );
3166        }
3167    }
3168
3169    /// If true, threads synchronizing with the write batch group leader will wait for up to
3170    /// write_thread_max_yield_usec before blocking on a mutex. This can substantially improve
3171    /// throughput for concurrent workloads, regardless of whether allow_concurrent_memtable_write
3172    /// is enabled.
3173    ///
3174    /// Default: true
3175    pub fn set_enable_write_thread_adaptive_yield(&mut self, enabled: bool) {
3176        unsafe {
3177            ffi::rocksdb_options_set_enable_write_thread_adaptive_yield(
3178                self.inner,
3179                c_uchar::from(enabled),
3180            );
3181        }
3182    }
3183
3184    /// Specifies whether an iteration->Next() sequentially skips over keys with the same user-key or not.
3185    ///
3186    /// This number specifies the number of keys (with the same userkey)
3187    /// that will be sequentially skipped before a reseek is issued.
3188    ///
3189    /// Default: 8
3190    pub fn set_max_sequential_skip_in_iterations(&mut self, num: u64) {
3191        unsafe {
3192            ffi::rocksdb_options_set_max_sequential_skip_in_iterations(self.inner, num);
3193        }
3194    }
3195
3196    /// Enable direct I/O mode for reading
3197    /// they may or may not improve performance depending on the use case
3198    ///
3199    /// Files will be opened in "direct I/O" mode
3200    /// which means that data read from the disk will not be cached or
3201    /// buffered. The hardware buffer of the devices may however still
3202    /// be used. Memory mapped files are not impacted by these parameters.
3203    ///
3204    /// Default: false
3205    ///
3206    /// # Examples
3207    ///
3208    /// ```
3209    /// use rust_rocksdb::Options;
3210    ///
3211    /// let mut opts = Options::default();
3212    /// opts.set_use_direct_reads(true);
3213    /// ```
3214    pub fn set_use_direct_reads(&mut self, enabled: bool) {
3215        unsafe {
3216            ffi::rocksdb_options_set_use_direct_reads(self.inner, c_uchar::from(enabled));
3217        }
3218    }
3219
3220    /// Enable direct I/O mode for flush and compaction
3221    ///
3222    /// Files will be opened in "direct I/O" mode
3223    /// which means that data written to the disk will not be cached or
3224    /// buffered. The hardware buffer of the devices may however still
3225    /// be used. Memory mapped files are not impacted by these parameters.
3226    /// they may or may not improve performance depending on the use case
3227    ///
3228    /// Default: false
3229    ///
3230    /// # Examples
3231    ///
3232    /// ```
3233    /// use rust_rocksdb::Options;
3234    ///
3235    /// let mut opts = Options::default();
3236    /// opts.set_use_direct_io_for_flush_and_compaction(true);
3237    /// ```
3238    pub fn set_use_direct_io_for_flush_and_compaction(&mut self, enabled: bool) {
3239        unsafe {
3240            ffi::rocksdb_options_set_use_direct_io_for_flush_and_compaction(
3241                self.inner,
3242                c_uchar::from(enabled),
3243            );
3244        }
3245    }
3246
3247    /// Enable/disable child process inherit open files.
3248    ///
3249    /// Default: true
3250    pub fn set_is_fd_close_on_exec(&mut self, enabled: bool) {
3251        unsafe {
3252            ffi::rocksdb_options_set_is_fd_close_on_exec(self.inner, c_uchar::from(enabled));
3253        }
3254    }
3255
3256    /// Hints to the OS that it should not buffer disk I/O. Enabling this
3257    /// parameter may improve performance but increases pressure on the
3258    /// system cache.
3259    ///
3260    /// The exact behavior of this parameter is platform dependent.
3261    ///
3262    /// On POSIX systems, after RocksDB reads data from disk it will
3263    /// mark the pages as "unneeded". The operating system may or may not
3264    /// evict these pages from memory, reducing pressure on the system
3265    /// cache. If the disk block is requested again this can result in
3266    /// additional disk I/O.
3267    ///
3268    /// On WINDOWS systems, files will be opened in "unbuffered I/O" mode
3269    /// which means that data read from the disk will not be cached or
3270    /// bufferized. The hardware buffer of the devices may however still
3271    /// be used. Memory mapped files are not impacted by this parameter.
3272    ///
3273    /// Default: true
3274    ///
3275    /// # Examples
3276    ///
3277    /// ```
3278    /// use rust_rocksdb::Options;
3279    ///
3280    /// let mut opts = Options::default();
3281    /// #[allow(deprecated)]
3282    /// opts.set_allow_os_buffer(false);
3283    /// ```
3284    #[deprecated(
3285        since = "0.7.0",
3286        note = "replaced with set_use_direct_reads/set_use_direct_io_for_flush_and_compaction methods"
3287    )]
3288    pub fn set_allow_os_buffer(&mut self, is_allow: bool) {
3289        self.set_use_direct_reads(!is_allow);
3290        self.set_use_direct_io_for_flush_and_compaction(!is_allow);
3291    }
3292
3293    /// Sets the number of shards used for table cache.
3294    ///
3295    /// Default: `6`
3296    ///
3297    /// # Examples
3298    ///
3299    /// ```
3300    /// use rust_rocksdb::Options;
3301    ///
3302    /// let mut opts = Options::default();
3303    /// opts.set_table_cache_num_shard_bits(4);
3304    /// ```
3305    pub fn set_table_cache_num_shard_bits(&mut self, nbits: c_int) {
3306        unsafe {
3307            ffi::rocksdb_options_set_table_cache_numshardbits(self.inner, nbits);
3308        }
3309    }
3310
3311    /// By default target_file_size_multiplier is 1, which means
3312    /// by default files in different levels will have similar size.
3313    ///
3314    /// Dynamically changeable through SetOptions() API
3315    pub fn set_target_file_size_multiplier(&mut self, multiplier: i32) {
3316        unsafe {
3317            ffi::rocksdb_options_set_target_file_size_multiplier(self.inner, multiplier as c_int);
3318        }
3319    }
3320
3321    /// Sets the minimum number of write buffers that will be merged
3322    /// before writing to storage.  If set to `1`, then
3323    /// all write buffers are flushed to L0 as individual files and this increases
3324    /// read amplification because a get request has to check in all of these
3325    /// files. Also, an in-memory merge may result in writing lesser
3326    /// data to storage if there are duplicate records in each of these
3327    /// individual write buffers.
3328    ///
3329    /// Default: `1`
3330    ///
3331    /// # Examples
3332    ///
3333    /// ```
3334    /// use rust_rocksdb::Options;
3335    ///
3336    /// let mut opts = Options::default();
3337    /// opts.set_min_write_buffer_number(2);
3338    /// ```
3339    pub fn set_min_write_buffer_number(&mut self, nbuf: c_int) {
3340        unsafe {
3341            ffi::rocksdb_options_set_min_write_buffer_number_to_merge(self.inner, nbuf);
3342        }
3343    }
3344
3345    /// Sets the maximum number of write buffers that are built up in memory.
3346    /// The default and the minimum number is 2, so that when 1 write buffer
3347    /// is being flushed to storage, new writes can continue to the other
3348    /// write buffer.
3349    /// If max_write_buffer_number > 3, writing will be slowed down to
3350    /// options.delayed_write_rate if we are writing to the last write buffer
3351    /// allowed.
3352    ///
3353    /// Default: `2`
3354    ///
3355    /// # Examples
3356    ///
3357    /// ```
3358    /// use rust_rocksdb::Options;
3359    ///
3360    /// let mut opts = Options::default();
3361    /// opts.set_max_write_buffer_number(4);
3362    /// ```
3363    pub fn set_max_write_buffer_number(&mut self, nbuf: c_int) {
3364        unsafe {
3365            ffi::rocksdb_options_set_max_write_buffer_number(self.inner, nbuf);
3366        }
3367    }
3368
3369    /// Sets the amount of data to build up in memory (backed by an unsorted log
3370    /// on disk) before converting to a sorted on-disk file.
3371    ///
3372    /// Larger values increase performance, especially during bulk loads.
3373    /// Up to max_write_buffer_number write buffers may be held in memory
3374    /// at the same time,
3375    /// so you may wish to adjust this parameter to control memory usage.
3376    /// Also, a larger write buffer will result in a longer recovery time
3377    /// the next time the database is opened.
3378    ///
3379    /// Note that write_buffer_size is enforced per column family.
3380    /// See db_write_buffer_size for sharing memory across column families.
3381    ///
3382    /// Default: `0x4000000` (64MiB)
3383    ///
3384    /// Dynamically changeable through SetOptions() API
3385    ///
3386    /// # Examples
3387    ///
3388    /// ```
3389    /// use rust_rocksdb::Options;
3390    ///
3391    /// let mut opts = Options::default();
3392    /// opts.set_write_buffer_size(128 * 1024 * 1024);
3393    /// ```
3394    pub fn set_write_buffer_size(&mut self, size: usize) {
3395        unsafe {
3396            ffi::rocksdb_options_set_write_buffer_size(self.inner, size);
3397        }
3398    }
3399
3400    /// Amount of data to build up in memtables across all column
3401    /// families before writing to disk.
3402    ///
3403    /// This is distinct from write_buffer_size, which enforces a limit
3404    /// for a single memtable.
3405    ///
3406    /// This feature is disabled by default. Specify a non-zero value
3407    /// to enable it.
3408    ///
3409    /// Default: 0 (disabled)
3410    ///
3411    /// # Examples
3412    ///
3413    /// ```
3414    /// use rust_rocksdb::Options;
3415    ///
3416    /// let mut opts = Options::default();
3417    /// opts.set_db_write_buffer_size(128 * 1024 * 1024);
3418    /// ```
3419    pub fn set_db_write_buffer_size(&mut self, size: usize) {
3420        unsafe {
3421            ffi::rocksdb_options_set_db_write_buffer_size(self.inner, size);
3422        }
3423    }
3424
3425    /// Control maximum total data size for a level.
3426    /// max_bytes_for_level_base is the max total for level-1.
3427    /// Maximum number of bytes for level L can be calculated as
3428    /// (max_bytes_for_level_base) * (max_bytes_for_level_multiplier ^ (L-1))
3429    /// For example, if max_bytes_for_level_base is 200MB, and if
3430    /// max_bytes_for_level_multiplier is 10, total data size for level-1
3431    /// will be 200MB, total file size for level-2 will be 2GB,
3432    /// and total file size for level-3 will be 20GB.
3433    ///
3434    /// Default: `0x10000000` (256MiB).
3435    ///
3436    /// Dynamically changeable through SetOptions() API
3437    ///
3438    /// # Examples
3439    ///
3440    /// ```
3441    /// use rust_rocksdb::Options;
3442    ///
3443    /// let mut opts = Options::default();
3444    /// opts.set_max_bytes_for_level_base(512 * 1024 * 1024);
3445    /// ```
3446    pub fn set_max_bytes_for_level_base(&mut self, size: u64) {
3447        unsafe {
3448            ffi::rocksdb_options_set_max_bytes_for_level_base(self.inner, size);
3449        }
3450    }
3451
3452    /// Default: `10`
3453    ///
3454    /// # Examples
3455    ///
3456    /// ```
3457    /// use rust_rocksdb::Options;
3458    ///
3459    /// let mut opts = Options::default();
3460    /// opts.set_max_bytes_for_level_multiplier(4.0);
3461    /// ```
3462    pub fn set_max_bytes_for_level_multiplier(&mut self, mul: f64) {
3463        unsafe {
3464            ffi::rocksdb_options_set_max_bytes_for_level_multiplier(self.inner, mul);
3465        }
3466    }
3467
3468    /// Sets a lower bound on the auto-tuned MANIFEST size limit. The MANIFEST
3469    /// is rolled over on reaching the limit and the older one is deleted.
3470    ///
3471    /// This used to be a hard limit. RocksDB now auto-tunes the real limit and
3472    /// treats this as a minimum, so setting it small does not keep the MANIFEST
3473    /// small. Batches written in the foreground get a 25% higher limit.
3474    ///
3475    /// Default: 1 GiB.
3476    ///
3477    /// # Examples
3478    ///
3479    /// ```
3480    /// use rust_rocksdb::Options;
3481    ///
3482    /// let mut opts = Options::default();
3483    /// opts.set_max_manifest_file_size(20 * 1024 * 1024);
3484    /// ```
3485    pub fn set_max_manifest_file_size(&mut self, size: usize) {
3486        unsafe {
3487            ffi::rocksdb_options_set_max_manifest_file_size(self.inner, size);
3488        }
3489    }
3490
3491    /// Sets the target file size for compaction.
3492    /// target_file_size_base is per-file size for level-1.
3493    /// Target file size for level L can be calculated by
3494    /// target_file_size_base * (target_file_size_multiplier ^ (L-1))
3495    /// For example, if target_file_size_base is 2MB and
3496    /// target_file_size_multiplier is 10, then each file on level-1 will
3497    /// be 2MB, and each file on level 2 will be 20MB,
3498    /// and each file on level-3 will be 200MB.
3499    ///
3500    /// Default: `0x4000000` (64MiB)
3501    ///
3502    /// Dynamically changeable through SetOptions() API
3503    ///
3504    /// # Examples
3505    ///
3506    /// ```
3507    /// use rust_rocksdb::Options;
3508    ///
3509    /// let mut opts = Options::default();
3510    /// opts.set_target_file_size_base(128 * 1024 * 1024);
3511    /// ```
3512    pub fn set_target_file_size_base(&mut self, size: u64) {
3513        unsafe {
3514            ffi::rocksdb_options_set_target_file_size_base(self.inner, size);
3515        }
3516    }
3517
3518    /// Sets the minimum number of write buffers that will be merged together
3519    /// before writing to storage.  If set to `1`, then
3520    /// all write buffers are flushed to L0 as individual files and this increases
3521    /// read amplification because a get request has to check in all of these
3522    /// files. Also, an in-memory merge may result in writing lesser
3523    /// data to storage if there are duplicate records in each of these
3524    /// individual write buffers.
3525    ///
3526    /// Default: `1`
3527    ///
3528    /// # Examples
3529    ///
3530    /// ```
3531    /// use rust_rocksdb::Options;
3532    ///
3533    /// let mut opts = Options::default();
3534    /// opts.set_min_write_buffer_number_to_merge(2);
3535    /// ```
3536    pub fn set_min_write_buffer_number_to_merge(&mut self, to_merge: c_int) {
3537        unsafe {
3538            ffi::rocksdb_options_set_min_write_buffer_number_to_merge(self.inner, to_merge);
3539        }
3540    }
3541
3542    /// Sets the number of files to trigger level-0 compaction. A value < `0` means that
3543    /// level-0 compaction will not be triggered by number of files at all.
3544    ///
3545    /// Default: `4`
3546    ///
3547    /// Dynamically changeable through SetOptions() API
3548    ///
3549    /// # Examples
3550    ///
3551    /// ```
3552    /// use rust_rocksdb::Options;
3553    ///
3554    /// let mut opts = Options::default();
3555    /// opts.set_level_zero_file_num_compaction_trigger(8);
3556    /// ```
3557    pub fn set_level_zero_file_num_compaction_trigger(&mut self, n: c_int) {
3558        unsafe {
3559            ffi::rocksdb_options_set_level0_file_num_compaction_trigger(self.inner, n);
3560        }
3561    }
3562
3563    /// Sets the soft limit on number of level-0 files. We start slowing down writes at this
3564    /// point. A value < `0` means that no writing slowdown will be triggered by
3565    /// number of files in level-0.
3566    ///
3567    /// Default: `20`
3568    ///
3569    /// Dynamically changeable through SetOptions() API
3570    ///
3571    /// # Examples
3572    ///
3573    /// ```
3574    /// use rust_rocksdb::Options;
3575    ///
3576    /// let mut opts = Options::default();
3577    /// opts.set_level_zero_slowdown_writes_trigger(10);
3578    /// ```
3579    pub fn set_level_zero_slowdown_writes_trigger(&mut self, n: c_int) {
3580        unsafe {
3581            ffi::rocksdb_options_set_level0_slowdown_writes_trigger(self.inner, n);
3582        }
3583    }
3584
3585    /// Sets the maximum number of level-0 files.  We stop writes at this point.
3586    ///
3587    /// Default: `36`
3588    ///
3589    /// Dynamically changeable through SetOptions() API
3590    ///
3591    /// # Examples
3592    ///
3593    /// ```
3594    /// use rust_rocksdb::Options;
3595    ///
3596    /// let mut opts = Options::default();
3597    /// opts.set_level_zero_stop_writes_trigger(48);
3598    /// ```
3599    pub fn set_level_zero_stop_writes_trigger(&mut self, n: c_int) {
3600        unsafe {
3601            ffi::rocksdb_options_set_level0_stop_writes_trigger(self.inner, n);
3602        }
3603    }
3604
3605    /// Sets the compaction style.
3606    ///
3607    /// Default: DBCompactionStyle::Level
3608    ///
3609    /// # Examples
3610    ///
3611    /// ```
3612    /// use rust_rocksdb::{Options, DBCompactionStyle};
3613    ///
3614    /// let mut opts = Options::default();
3615    /// opts.set_compaction_style(DBCompactionStyle::Universal);
3616    /// ```
3617    pub fn set_compaction_style(&mut self, style: DBCompactionStyle) {
3618        unsafe {
3619            ffi::rocksdb_options_set_compaction_style(self.inner, style as c_int);
3620        }
3621    }
3622
3623    /// The compaction style set by [`Self::set_compaction_style`].
3624    ///
3625    /// `None` means `kCompactionStyleNone`, which this crate does not name. That style turns
3626    /// background compaction off entirely and only runs work submitted through
3627    /// `CompactFiles`.
3628    pub fn get_compaction_style(&self) -> Option<DBCompactionStyle> {
3629        let raw = unsafe { ffi::rocksdb_options_get_compaction_style(self.inner) };
3630        DBCompactionStyle::try_from_raw(raw)
3631    }
3632
3633    /// Sets the options needed to support Universal Style compactions.
3634    pub fn set_universal_compaction_options(&mut self, uco: &UniversalCompactOptions) {
3635        unsafe {
3636            ffi::rocksdb_options_set_universal_compaction_options(self.inner, uco.inner);
3637        }
3638    }
3639
3640    /// Sets the options for FIFO compaction style.
3641    pub fn set_fifo_compaction_options(&mut self, fco: &FifoCompactOptions) {
3642        unsafe {
3643            ffi::rocksdb_options_set_fifo_compaction_options(self.inner, fco.inner);
3644        }
3645    }
3646
3647    /// Sets unordered_write to true trades higher write throughput with
3648    /// relaxing the immutability guarantee of snapshots. This violates the
3649    /// repeatability one expects from ::Get from a snapshot, as well as
3650    /// ::MultiGet and Iterator's consistent-point-in-time view property.
3651    /// If the application cannot tolerate the relaxed guarantees, it can implement
3652    /// its own mechanisms to work around that and yet benefit from the higher
3653    /// throughput. Using TransactionDB with WRITE_PREPARED write policy and
3654    /// two_write_queues=true is one way to achieve immutable snapshots despite
3655    /// unordered_write.
3656    ///
3657    /// By default, i.e., when it is false, rocksdb does not advance the sequence
3658    /// number for new snapshots unless all the writes with lower sequence numbers
3659    /// are already finished. This provides the immutability that we expect from
3660    /// snapshots. Moreover, since Iterator and MultiGet internally depend on
3661    /// snapshots, the snapshot immutability results into Iterator and MultiGet
3662    /// offering consistent-point-in-time view. If set to true, although
3663    /// Read-Your-Own-Write property is still provided, the snapshot immutability
3664    /// property is relaxed: the writes issued after the snapshot is obtained (with
3665    /// larger sequence numbers) will be still not visible to the reads from that
3666    /// snapshot, however, there still might be pending writes (with lower sequence
3667    /// number) that will change the state visible to the snapshot after they are
3668    /// landed to the memtable.
3669    ///
3670    /// Default: false
3671    pub fn set_unordered_write(&mut self, unordered: bool) {
3672        unsafe {
3673            ffi::rocksdb_options_set_unordered_write(self.inner, c_uchar::from(unordered));
3674        }
3675    }
3676
3677    /// Sets maximum number of threads that will
3678    /// concurrently perform a compaction job by breaking it into multiple,
3679    /// smaller ones that are run simultaneously.
3680    ///
3681    /// Default: 1 (i.e. no subcompactions)
3682    pub fn set_max_subcompactions(&mut self, num: u32) {
3683        unsafe {
3684            ffi::rocksdb_options_set_max_subcompactions(self.inner, num);
3685        }
3686    }
3687
3688    /// Sets maximum number of concurrent background jobs
3689    /// (compactions and flushes).
3690    ///
3691    /// Default: 2
3692    ///
3693    /// Dynamically changeable through SetDBOptions() API.
3694    pub fn set_max_background_jobs(&mut self, jobs: c_int) {
3695        unsafe {
3696            ffi::rocksdb_options_set_max_background_jobs(self.inner, jobs);
3697        }
3698    }
3699
3700    /// Sets the maximum number of concurrent background compaction jobs, submitted to
3701    /// the default LOW priority thread pool.
3702    /// We first try to schedule compactions based on
3703    /// `base_background_compactions`. If the compaction cannot catch up , we
3704    /// will increase number of compaction threads up to
3705    /// `max_background_compactions`.
3706    ///
3707    /// If you're increasing this, also consider increasing number of threads in
3708    /// LOW priority thread pool. For more information, see
3709    /// Env::SetBackgroundThreads
3710    ///
3711    /// Default: `-1`, meaning RocksDB derives it from `max_background_jobs`.
3712    /// Setting either this or `max_background_flushes` opts into the old
3713    /// behaviour, where the unset one of the pair counts as `1`.
3714    ///
3715    /// # Examples
3716    ///
3717    /// ```
3718    /// use rust_rocksdb::Options;
3719    ///
3720    /// let mut opts = Options::default();
3721    /// #[allow(deprecated)]
3722    /// opts.set_max_background_compactions(2);
3723    /// ```
3724    #[deprecated(
3725        since = "0.15.0",
3726        note = "RocksDB automatically decides this based on the value of max_background_jobs"
3727    )]
3728    pub fn set_max_background_compactions(&mut self, n: c_int) {
3729        unsafe {
3730            ffi::rocksdb_options_set_max_background_compactions(self.inner, n);
3731        }
3732    }
3733
3734    /// The raw `max_background_compactions` field, `-1` while it is unset.
3735    ///
3736    /// Deprecated upstream in favour of `max_background_jobs`, so this is the value someone
3737    /// passed to [`Self::set_max_background_compactions`], not the concurrency RocksDB will
3738    /// actually run. While it is `-1` the real limit comes from
3739    /// [`Self::get_max_background_jobs`], unless `max_background_flushes` is set, in which
3740    /// case this half of the pair counts as `1`. RocksDB resolves that on a copy when the DB
3741    /// opens and never writes it back here.
3742    pub fn get_max_background_compactions(&self) -> c_int {
3743        unsafe { ffi::rocksdb_options_get_max_background_compactions(self.inner) }
3744    }
3745
3746    /// Sets the maximum number of concurrent background memtable flush jobs, submitted to
3747    /// the HIGH priority thread pool.
3748    ///
3749    /// By default, all background jobs (major compaction and memtable flush) go
3750    /// to the LOW priority pool. If this option is set to a positive number,
3751    /// memtable flush jobs will be submitted to the HIGH priority pool.
3752    /// It is important when the same Env is shared by multiple db instances.
3753    /// Without a separate pool, long running major compaction jobs could
3754    /// potentially block memtable flush jobs of other db instances, leading to
3755    /// unnecessary Put stalls.
3756    ///
3757    /// If you're increasing this, also consider increasing number of threads in
3758    /// HIGH priority thread pool. For more information, see
3759    /// Env::SetBackgroundThreads
3760    ///
3761    /// Default: `-1`, meaning RocksDB derives it from `max_background_jobs`.
3762    /// Setting either this or `max_background_compactions` opts into the old
3763    /// behaviour, where the unset one of the pair counts as `1`.
3764    ///
3765    /// # Examples
3766    ///
3767    /// ```
3768    /// use rust_rocksdb::Options;
3769    ///
3770    /// let mut opts = Options::default();
3771    /// #[allow(deprecated)]
3772    /// opts.set_max_background_flushes(2);
3773    /// ```
3774    #[deprecated(
3775        since = "0.15.0",
3776        note = "RocksDB automatically decides this based on the value of max_background_jobs"
3777    )]
3778    pub fn set_max_background_flushes(&mut self, n: c_int) {
3779        unsafe {
3780            ffi::rocksdb_options_set_max_background_flushes(self.inner, n);
3781        }
3782    }
3783
3784    /// The raw `max_background_flushes` field, `-1` while it is unset.
3785    ///
3786    /// Deprecated upstream in favour of `max_background_jobs`, so this is the value someone
3787    /// passed to [`Self::set_max_background_flushes`], not the concurrency RocksDB will
3788    /// actually run. While it is `-1` the real limit comes from
3789    /// [`Self::get_max_background_jobs`], unless `max_background_compactions` is set, in
3790    /// which case this half of the pair counts as `1`. RocksDB resolves that on a copy when
3791    /// the DB opens and never writes it back here.
3792    pub fn get_max_background_flushes(&self) -> c_int {
3793        unsafe { ffi::rocksdb_options_get_max_background_flushes(self.inner) }
3794    }
3795
3796    /// Disables automatic compactions. Manual compactions can still
3797    /// be issued on this column family
3798    ///
3799    /// Default: `false`
3800    ///
3801    /// Dynamically changeable through SetOptions() API
3802    ///
3803    /// # Examples
3804    ///
3805    /// ```
3806    /// use rust_rocksdb::Options;
3807    ///
3808    /// let mut opts = Options::default();
3809    /// opts.set_disable_auto_compactions(true);
3810    /// ```
3811    pub fn set_disable_auto_compactions(&mut self, disable: bool) {
3812        unsafe {
3813            ffi::rocksdb_options_set_disable_auto_compactions(self.inner, c_int::from(disable));
3814        }
3815    }
3816
3817    /// SetMemtableHugePageSize sets the page size for huge page for
3818    /// arena used by the memtable.
3819    /// If <=0, it won't allocate from huge page but from malloc.
3820    /// Users are responsible to reserve huge pages for it to be allocated. For
3821    /// example:
3822    ///      sysctl -w vm.nr_hugepages=20
3823    /// See linux doc Documentation/vm/hugetlbpage.txt
3824    /// If there isn't enough free huge page available, it will fall back to
3825    /// malloc.
3826    ///
3827    /// Dynamically changeable through SetOptions() API
3828    pub fn set_memtable_huge_page_size(&mut self, size: size_t) {
3829        unsafe {
3830            ffi::rocksdb_options_set_memtable_huge_page_size(self.inner, size);
3831        }
3832    }
3833
3834    /// Enables the skip-list memtable's batch-lookup optimization for
3835    /// `MultiGet`.
3836    ///
3837    /// When enabled, the search path is cached between consecutive keys in a
3838    /// `MultiGet`, reducing per-key cost from `O(log N)` to `O(log d)` where
3839    /// `d` is the distance between consecutive keys. The optimization
3840    /// exploits the fact that `MultiGet` keys are sorted.
3841    ///
3842    /// Applies only to the default skip-list memtable (the one used when no
3843    /// memtable factory is set via [`Self::set_memtable_factory`]). The
3844    /// `MemtableFactory::Vector`, `HashSkipList`, and `HashLinkList` variants
3845    /// all fall back to per-key lookups regardless of this flag.
3846    ///
3847    /// This option is immutable on the C++ side: it must be set before the
3848    /// column family is opened and cannot be changed via `SetOptions`.
3849    ///
3850    /// Default: `false`
3851    pub fn set_memtable_batch_lookup_optimization(&mut self, enable: bool) {
3852        unsafe {
3853            ffi::rocksdb_options_set_memtable_batch_lookup_optimization(
3854                self.inner,
3855                c_uchar::from(enable),
3856            );
3857        }
3858    }
3859
3860    /// Returns the current value of
3861    /// [`Self::set_memtable_batch_lookup_optimization`].
3862    ///
3863    /// Provided primarily for tests that want to confirm the setter is wired
3864    /// through to the underlying C++ `AdvancedColumnFamilyOptions`.
3865    pub fn get_memtable_batch_lookup_optimization(&self) -> bool {
3866        unsafe { ffi::rocksdb_options_get_memtable_batch_lookup_optimization(self.inner) != 0 }
3867    }
3868
3869    /// Sets the maximum number of successive merge operations on a key in the memtable.
3870    ///
3871    /// When a merge operation is added to the memtable and the maximum number of
3872    /// successive merges is reached, the value of the key will be calculated and
3873    /// inserted into the memtable instead of the merge operation. This will
3874    /// ensure that there are never more than max_successive_merges merge
3875    /// operations in the memtable.
3876    ///
3877    /// Default: 0 (disabled)
3878    pub fn set_max_successive_merges(&mut self, num: usize) {
3879        unsafe {
3880            ffi::rocksdb_options_set_max_successive_merges(self.inner, num);
3881        }
3882    }
3883
3884    /// Control locality of bloom filter probes to improve cache miss rate.
3885    /// This option only applies to memtable prefix bloom and plaintable
3886    /// prefix bloom. It essentially limits the max number of cache lines each
3887    /// bloom filter check can touch.
3888    ///
3889    /// This optimization is turned off when set to 0. The number should never
3890    /// be greater than number of probes. This option can boost performance
3891    /// for in-memory workload but should use with care since it can cause
3892    /// higher false positive rate.
3893    ///
3894    /// Default: 0
3895    pub fn set_bloom_locality(&mut self, v: u32) {
3896        unsafe {
3897            ffi::rocksdb_options_set_bloom_locality(self.inner, v);
3898        }
3899    }
3900
3901    /// Enable/disable thread-safe inplace updates.
3902    ///
3903    /// Requires updates if
3904    /// * key exists in current memtable
3905    /// * new sizeof(new_value) <= sizeof(old_value)
3906    /// * old_value for that key is a put i.e. kTypeValue
3907    ///
3908    /// Default: false.
3909    pub fn set_inplace_update_support(&mut self, enabled: bool) {
3910        unsafe {
3911            ffi::rocksdb_options_set_inplace_update_support(self.inner, c_uchar::from(enabled));
3912        }
3913    }
3914
3915    /// Sets the number of locks used for inplace update.
3916    ///
3917    /// Default: 10000 when inplace_update_support = true, otherwise 0.
3918    pub fn set_inplace_update_locks(&mut self, num: usize) {
3919        unsafe {
3920            ffi::rocksdb_options_set_inplace_update_num_locks(self.inner, num);
3921        }
3922    }
3923
3924    /// Different max-size multipliers for different levels.
3925    /// These are multiplied by max_bytes_for_level_multiplier to arrive
3926    /// at the max-size of each level.
3927    ///
3928    /// Default: 1
3929    ///
3930    /// Dynamically changeable through SetOptions() API
3931    pub fn set_max_bytes_for_level_multiplier_additional(&mut self, level_values: &[i32]) {
3932        let count = level_values.len();
3933        unsafe {
3934            ffi::rocksdb_options_set_max_bytes_for_level_multiplier_additional(
3935                self.inner,
3936                level_values.as_ptr().cast_mut(),
3937                count,
3938            );
3939        }
3940    }
3941
3942    /// The total maximum size(bytes) of write buffers to maintain in memory
3943    /// including copies of buffers that have already been flushed. This parameter
3944    /// only affects trimming of flushed buffers and does not affect flushing.
3945    /// This controls the maximum amount of write history that will be available
3946    /// in memory for conflict checking when Transactions are used. The actual
3947    /// size of write history (flushed Memtables) might be higher than this limit
3948    /// if further trimming will reduce write history total size below this
3949    /// limit. For example, if max_write_buffer_size_to_maintain is set to 64MB,
3950    /// and there are three flushed Memtables, with sizes of 32MB, 20MB, 20MB.
3951    /// Because trimming the next Memtable of size 20MB will reduce total memory
3952    /// usage to 52MB which is below the limit, RocksDB will stop trimming.
3953    ///
3954    /// When using an OptimisticTransactionDB:
3955    /// If this value is too low, some transactions may fail at commit time due
3956    /// to not being able to determine whether there were any write conflicts.
3957    ///
3958    /// When using a TransactionDB:
3959    /// If Transaction::SetSnapshot is used, TransactionDB will read either
3960    /// in-memory write buffers or SST files to do write-conflict checking.
3961    /// Increasing this value can reduce the number of reads to SST files
3962    /// done for conflict detection.
3963    ///
3964    /// Setting this value to 0 will cause write buffers to be freed immediately
3965    /// after they are flushed. If this value is set to -1,
3966    /// 'max_write_buffer_number * write_buffer_size' will be used.
3967    ///
3968    /// Default:
3969    /// If using a TransactionDB/OptimisticTransactionDB, the default value will
3970    /// be set to the value of 'max_write_buffer_number * write_buffer_size'
3971    /// if it is not explicitly set by the user.  Otherwise, the default is 0.
3972    pub fn set_max_write_buffer_size_to_maintain(&mut self, size: i64) {
3973        unsafe {
3974            ffi::rocksdb_options_set_max_write_buffer_size_to_maintain(self.inner, size);
3975        }
3976    }
3977
3978    /// By default, a single write thread queue is maintained. The thread gets
3979    /// to the head of the queue becomes write batch group leader and responsible
3980    /// for writing to WAL and memtable for the batch group.
3981    ///
3982    /// If enable_pipelined_write is true, separate write thread queue is
3983    /// maintained for WAL write and memtable write. A write thread first enter WAL
3984    /// writer queue and then memtable writer queue. Pending thread on the WAL
3985    /// writer queue thus only have to wait for previous writers to finish their
3986    /// WAL writing but not the memtable writing. Enabling the feature may improve
3987    /// write throughput and reduce latency of the prepare phase of two-phase
3988    /// commit.
3989    ///
3990    /// Default: false
3991    pub fn set_enable_pipelined_write(&mut self, value: bool) {
3992        unsafe {
3993            ffi::rocksdb_options_set_enable_pipelined_write(self.inner, c_uchar::from(value));
3994        }
3995    }
3996
3997    /// Defines the underlying memtable implementation.
3998    /// See official [wiki](https://github.com/facebook/rocksdb/wiki/MemTable) for more information.
3999    /// Defaults to using a skiplist.
4000    ///
4001    /// # Examples
4002    ///
4003    /// ```
4004    /// use rust_rocksdb::{Options, MemtableFactory};
4005    /// let mut opts = Options::default();
4006    /// let factory = MemtableFactory::HashSkipList {
4007    ///     bucket_count: 1_000_000,
4008    ///     height: 4,
4009    ///     branching_factor: 4,
4010    /// };
4011    ///
4012    /// opts.set_allow_concurrent_memtable_write(false);
4013    /// opts.set_memtable_factory(factory);
4014    /// ```
4015    pub fn set_memtable_factory(&mut self, factory: MemtableFactory) {
4016        match factory {
4017            MemtableFactory::Vector => unsafe {
4018                ffi::rocksdb_options_set_memtable_vector_rep(self.inner);
4019            },
4020            MemtableFactory::HashSkipList {
4021                bucket_count,
4022                height,
4023                branching_factor,
4024            } => unsafe {
4025                ffi::rocksdb_options_set_hash_skip_list_rep(
4026                    self.inner,
4027                    bucket_count,
4028                    height,
4029                    branching_factor,
4030                );
4031            },
4032            MemtableFactory::HashLinkList { bucket_count } => unsafe {
4033                ffi::rocksdb_options_set_hash_link_list_rep(self.inner, bucket_count);
4034            },
4035        }
4036    }
4037
4038    pub fn set_block_based_table_factory(&mut self, factory: &BlockBasedOptions) {
4039        unsafe {
4040            ffi::rocksdb_options_set_block_based_table_factory(self.inner, factory.inner);
4041        }
4042        self.outlive.block_based = Some(factory.outlive.clone());
4043    }
4044
4045    /// Sets the table factory to a CuckooTableFactory (the default table
4046    /// factory is a block-based table factory that provides a default
4047    /// implementation of TableBuilder and TableReader with default
4048    /// BlockBasedTableOptions).
4049    /// See official [wiki](https://github.com/facebook/rocksdb/wiki/CuckooTable-Format) for more information on this table format.
4050    /// # Examples
4051    ///
4052    /// ```
4053    /// use rust_rocksdb::{Options, CuckooTableOptions};
4054    ///
4055    /// let mut opts = Options::default();
4056    /// let mut factory_opts = CuckooTableOptions::default();
4057    /// factory_opts.set_hash_ratio(0.8);
4058    /// factory_opts.set_max_search_depth(20);
4059    /// factory_opts.set_cuckoo_block_size(10);
4060    /// factory_opts.set_identity_as_first_hash(true);
4061    /// factory_opts.set_use_module_hash(false);
4062    ///
4063    /// opts.set_cuckoo_table_factory(&factory_opts);
4064    /// ```
4065    pub fn set_cuckoo_table_factory(&mut self, factory: &CuckooTableOptions) {
4066        unsafe {
4067            ffi::rocksdb_options_set_cuckoo_table_factory(self.inner, factory.inner);
4068        }
4069    }
4070
4071    // This is a factory that provides TableFactory objects.
4072    // Default: a block-based table factory that provides a default
4073    // implementation of TableBuilder and TableReader with default
4074    // BlockBasedTableOptions.
4075    /// Sets the factory as plain table.
4076    /// See official [wiki](https://github.com/facebook/rocksdb/wiki/PlainTable-Format) for more
4077    /// information.
4078    ///
4079    /// # Examples
4080    ///
4081    /// ```
4082    /// use rust_rocksdb::{KeyEncodingType, Options, PlainTableFactoryOptions};
4083    ///
4084    /// let mut opts = Options::default();
4085    /// let factory_opts = PlainTableFactoryOptions {
4086    ///   user_key_length: 0,
4087    ///   bloom_bits_per_key: 20,
4088    ///   hash_table_ratio: 0.75,
4089    ///   index_sparseness: 16,
4090    ///   huge_page_tlb_size: 0,
4091    ///   encoding_type: KeyEncodingType::Plain,
4092    ///   full_scan_mode: false,
4093    ///   store_index_in_file: false,
4094    /// };
4095    ///
4096    /// opts.set_plain_table_factory(&factory_opts);
4097    /// ```
4098    pub fn set_plain_table_factory(&mut self, options: &PlainTableFactoryOptions) {
4099        unsafe {
4100            ffi::rocksdb_options_set_plain_table_factory(
4101                self.inner,
4102                options.user_key_length,
4103                options.bloom_bits_per_key,
4104                options.hash_table_ratio,
4105                options.index_sparseness,
4106                options.huge_page_tlb_size,
4107                options.encoding_type as c_char,
4108                c_uchar::from(options.full_scan_mode),
4109                c_uchar::from(options.store_index_in_file),
4110            );
4111        }
4112    }
4113
4114    /// Sets the start level to use compression.
4115    pub fn set_min_level_to_compress(&mut self, lvl: c_int) {
4116        unsafe {
4117            ffi::rocksdb_options_set_min_level_to_compress(self.inner, lvl);
4118        }
4119    }
4120
4121    /// Measure IO stats in compactions and flushes, if `true`.
4122    ///
4123    /// Default: `false`
4124    ///
4125    /// # Examples
4126    ///
4127    /// ```
4128    /// use rust_rocksdb::Options;
4129    ///
4130    /// let mut opts = Options::default();
4131    /// opts.set_report_bg_io_stats(true);
4132    /// ```
4133    pub fn set_report_bg_io_stats(&mut self, enable: bool) {
4134        unsafe {
4135            ffi::rocksdb_options_set_report_bg_io_stats(self.inner, c_int::from(enable));
4136        }
4137    }
4138
4139    /// Once write-ahead logs exceed this size, we will start forcing the flush of
4140    /// column families whose memtables are backed by the oldest live WAL file
4141    /// (i.e. the ones that are causing all the space amplification).
4142    ///
4143    /// Default: `0`
4144    ///
4145    /// # Examples
4146    ///
4147    /// ```
4148    /// use rust_rocksdb::Options;
4149    ///
4150    /// let mut opts = Options::default();
4151    /// // Set max total wal size to 1G.
4152    /// opts.set_max_total_wal_size(1 << 30);
4153    /// ```
4154    pub fn set_max_total_wal_size(&mut self, size: u64) {
4155        unsafe {
4156            ffi::rocksdb_options_set_max_total_wal_size(self.inner, size);
4157        }
4158    }
4159
4160    /// Recovery mode to control the consistency while replaying WAL.
4161    ///
4162    /// Default: DBRecoveryMode::PointInTime
4163    ///
4164    /// # Examples
4165    ///
4166    /// ```
4167    /// use rust_rocksdb::{Options, DBRecoveryMode};
4168    ///
4169    /// let mut opts = Options::default();
4170    /// opts.set_wal_recovery_mode(DBRecoveryMode::AbsoluteConsistency);
4171    /// ```
4172    pub fn set_wal_recovery_mode(&mut self, mode: DBRecoveryMode) {
4173        unsafe {
4174            ffi::rocksdb_options_set_wal_recovery_mode(self.inner, mode as c_int);
4175        }
4176    }
4177
4178    /// The recovery mode set by [`Self::set_wal_recovery_mode`].
4179    ///
4180    /// [`DBRecoveryMode`] covers every mode RocksDB defines today, so `None` only shows up if
4181    /// a future release adds one.
4182    pub fn get_wal_recovery_mode(&self) -> Option<DBRecoveryMode> {
4183        let raw = unsafe { ffi::rocksdb_options_get_wal_recovery_mode(self.inner) };
4184        DBRecoveryMode::try_from_raw(raw)
4185    }
4186
4187    /// Enables recording RocksDB statistics.
4188    ///
4189    /// The statistics in this Options object are shared between all DB instances.
4190    /// See [`get_statistics`](Self::get_statistics), [`get_ticker_count`](Self::get_ticker_count),
4191    /// and [`get_histogram_data`](Self::get_histogram_data).
4192    pub fn enable_statistics(&mut self) {
4193        unsafe {
4194            ffi::rocksdb_options_enable_statistics(self.inner);
4195        }
4196    }
4197
4198    /// Returns a string containing RocksDB statistics if enabled using
4199    /// [`enable_statistics`](Self::enable_statistics).
4200    pub fn get_statistics(&self) -> Option<String> {
4201        unsafe {
4202            let value = ffi::rocksdb_options_statistics_get_string(self.inner);
4203            if value.is_null() {
4204                return None;
4205            }
4206
4207            // Must have valid UTF-8 format.
4208            Some(from_cstr_and_free(value))
4209        }
4210    }
4211
4212    /// StatsLevel can be used to reduce statistics overhead by skipping certain
4213    /// types of stats in the stats collection process.
4214    ///
4215    /// Only takes effect if stats are enabled first using
4216    /// [`enable_statistics`](Self::enable_statistics).
4217    pub fn set_statistics_level(&self, level: StatsLevel) {
4218        unsafe { ffi::rocksdb_options_set_statistics_level(self.inner, level as c_int) }
4219    }
4220
4221    /// The level set by [`Self::set_statistics_level`].
4222    ///
4223    /// Reports [`StatsLevel::DisableAll`] when statistics were never enabled,
4224    /// because that is what the C API returns with no statistics object attached.
4225    ///
4226    /// Returns `None` for a value this crate has no variant for, which should not
4227    /// happen: RocksDB clamps the level into range on the way in.
4228    pub fn get_statistics_level(&self) -> Option<StatsLevel> {
4229        let raw = unsafe { ffi::rocksdb_options_get_statistics_level(self.inner) };
4230        StatsLevel::try_from_raw(raw)
4231    }
4232
4233    /// Returns a counter if statistics are enabled using
4234    /// [`enable_statistics`](Self::enable_statistics).
4235    pub fn get_ticker_count(&self, ticker: Ticker) -> u64 {
4236        unsafe { ffi::rocksdb_options_statistics_get_ticker_count(self.inner, ticker as u32) }
4237    }
4238
4239    /// Returns a histogram if statistics are enabled using
4240    /// [`enable_statistics`](Self::enable_statistics).
4241    pub fn get_histogram_data(&self, histogram: Histogram) -> HistogramData {
4242        unsafe {
4243            let data = HistogramData::default();
4244            ffi::rocksdb_options_statistics_get_histogram_data(
4245                self.inner,
4246                histogram as u32,
4247                data.inner,
4248            );
4249            data
4250        }
4251    }
4252
4253    /// If not zero, dump `rocksdb.stats` to LOG every `stats_dump_period_sec`.
4254    ///
4255    /// Default: `600` (10 mins)
4256    ///
4257    /// # Examples
4258    ///
4259    /// ```
4260    /// use rust_rocksdb::Options;
4261    ///
4262    /// let mut opts = Options::default();
4263    /// opts.set_stats_dump_period_sec(300);
4264    /// ```
4265    pub fn set_stats_dump_period_sec(&mut self, period: c_uint) {
4266        unsafe {
4267            ffi::rocksdb_options_set_stats_dump_period_sec(self.inner, period);
4268        }
4269    }
4270
4271    /// If not zero, dump rocksdb.stats to RocksDB to LOG every `stats_persist_period_sec`.
4272    ///
4273    /// Default: `600` (10 mins)
4274    ///
4275    /// # Examples
4276    ///
4277    /// ```
4278    /// use rust_rocksdb::Options;
4279    ///
4280    /// let mut opts = Options::default();
4281    /// opts.set_stats_persist_period_sec(5);
4282    /// ```
4283    pub fn set_stats_persist_period_sec(&mut self, period: c_uint) {
4284        unsafe {
4285            ffi::rocksdb_options_set_stats_persist_period_sec(self.inner, period);
4286        }
4287    }
4288
4289    /// When set to true, reading SST files will opt out of the filesystem's
4290    /// readahead. Setting this to false may improve sequential iteration
4291    /// performance.
4292    ///
4293    /// Default: `true`
4294    pub fn set_advise_random_on_open(&mut self, advise: bool) {
4295        unsafe {
4296            ffi::rocksdb_options_set_advise_random_on_open(self.inner, c_uchar::from(advise));
4297        }
4298    }
4299
4300    /// Enable/disable adaptive mutex, which spins in the user space before resorting to kernel.
4301    ///
4302    /// This could reduce context switch when the mutex is not
4303    /// heavily contended. However, if the mutex is hot, we could end up
4304    /// wasting spin time.
4305    ///
4306    /// Default: false
4307    pub fn set_use_adaptive_mutex(&mut self, enabled: bool) {
4308        unsafe {
4309            ffi::rocksdb_options_set_use_adaptive_mutex(self.inner, c_uchar::from(enabled));
4310        }
4311    }
4312
4313    /// Sets the number of levels for this database.
4314    pub fn set_num_levels(&mut self, n: c_int) {
4315        unsafe {
4316            ffi::rocksdb_options_set_num_levels(self.inner, n);
4317        }
4318    }
4319
4320    /// When a `prefix_extractor` is defined through `opts.set_prefix_extractor` this
4321    /// creates a prefix bloom filter for each memtable with the size of
4322    /// `write_buffer_size * memtable_prefix_bloom_ratio` (capped at 0.25).
4323    ///
4324    /// Default: `0`
4325    ///
4326    /// # Examples
4327    ///
4328    /// ```
4329    /// use rust_rocksdb::{Options, SliceTransform};
4330    ///
4331    /// let mut opts = Options::default();
4332    /// let transform = SliceTransform::create_fixed_prefix(10);
4333    /// opts.set_prefix_extractor(transform);
4334    /// opts.set_memtable_prefix_bloom_ratio(0.2);
4335    /// ```
4336    pub fn set_memtable_prefix_bloom_ratio(&mut self, ratio: f64) {
4337        unsafe {
4338            ffi::rocksdb_options_set_memtable_prefix_bloom_size_ratio(self.inner, ratio);
4339        }
4340    }
4341
4342    /// Sets the maximum number of bytes in all compacted files.
4343    /// We try to limit number of bytes in one compaction to be lower than this
4344    /// threshold. But it's not guaranteed.
4345    ///
4346    /// Value 0 will be sanitized.
4347    ///
4348    /// Default: target_file_size_base * 25
4349    pub fn set_max_compaction_bytes(&mut self, nbytes: u64) {
4350        unsafe {
4351            ffi::rocksdb_options_set_max_compaction_bytes(self.inner, nbytes);
4352        }
4353    }
4354
4355    /// Specifies the absolute path of the directory the
4356    /// write-ahead log (WAL) should be written to.
4357    ///
4358    /// Default: same directory as the database
4359    ///
4360    /// # Examples
4361    ///
4362    /// ```
4363    /// use rust_rocksdb::Options;
4364    ///
4365    /// let mut opts = Options::default();
4366    /// opts.set_wal_dir("/path/to/dir");
4367    /// ```
4368    pub fn set_wal_dir<P: AsRef<Path>>(&mut self, path: P) {
4369        let p = to_cpath(path).unwrap();
4370        unsafe {
4371            ffi::rocksdb_options_set_wal_dir(self.inner, p.as_ptr());
4372        }
4373    }
4374
4375    /// The WAL directory set by [`Self::set_wal_dir`], empty when the WAL lives with the data.
4376    pub fn get_wal_dir(&self) -> String {
4377        let mut len: size_t = 0;
4378        let path = unsafe { ffi::rocksdb_options_get_wal_dir(self.inner, &raw mut len) };
4379        unsafe { borrowed_string(path, len) }
4380    }
4381
4382    /// Sets the WAL ttl in seconds.
4383    ///
4384    /// The following two options affect how archived logs will be deleted.
4385    /// 1. If both set to 0, logs will be deleted asap and will not get into
4386    ///    the archive.
4387    /// 2. If wal_ttl_seconds is 0 and wal_size_limit_mb is not 0,
4388    ///    WAL files will be checked every 10 min and if total size is greater
4389    ///    then wal_size_limit_mb, they will be deleted starting with the
4390    ///    earliest until size_limit is met. All empty files will be deleted.
4391    /// 3. If wal_ttl_seconds is not 0 and wall_size_limit_mb is 0, then
4392    ///    WAL files will be checked every wal_ttl_seconds / 2 and those that
4393    ///    are older than wal_ttl_seconds will be deleted.
4394    /// 4. If both are not 0, WAL files will be checked every 10 min and both
4395    ///    checks will be performed with ttl being first.
4396    ///
4397    /// Default: 0
4398    pub fn set_wal_ttl_seconds(&mut self, secs: u64) {
4399        unsafe {
4400            ffi::rocksdb_options_set_WAL_ttl_seconds(self.inner, secs);
4401        }
4402    }
4403
4404    /// Sets the WAL size limit in MB.
4405    ///
4406    /// If total size of WAL files is greater then wal_size_limit_mb,
4407    /// they will be deleted starting with the earliest until size_limit is met.
4408    ///
4409    /// Default: 0
4410    pub fn set_wal_size_limit_mb(&mut self, size: u64) {
4411        unsafe {
4412            ffi::rocksdb_options_set_WAL_size_limit_MB(self.inner, size);
4413        }
4414    }
4415
4416    /// Sets the number of bytes to preallocate (via fallocate) the manifest files.
4417    ///
4418    /// Default is 4MB, which is reasonable to reduce random IO
4419    /// as well as prevent overallocation for mounts that preallocate
4420    /// large amounts of data (such as xfs's allocsize option).
4421    pub fn set_manifest_preallocation_size(&mut self, size: usize) {
4422        unsafe {
4423            ffi::rocksdb_options_set_manifest_preallocation_size(self.inner, size);
4424        }
4425    }
4426
4427    /// If true, then DB::Open() will not update the statistics used to optimize
4428    /// compaction decision by loading table properties from many files.
4429    /// Turning off this feature will improve DBOpen time especially in disk environment.
4430    ///
4431    /// Default: false
4432    pub fn set_skip_stats_update_on_db_open(&mut self, skip: bool) {
4433        unsafe {
4434            ffi::rocksdb_options_set_skip_stats_update_on_db_open(self.inner, c_uchar::from(skip));
4435        }
4436    }
4437
4438    /// Controls whether RocksDB opens and validates SST files in the background after open.
4439    ///
4440    /// Enabling this can reduce open latency for databases with many SST files
4441    /// or high latency storage. It is mostly useful with
4442    /// [`Options::set_max_open_files`] set to `-1`.
4443    ///
4444    /// This option is not compatible with FIFO compaction and requires
4445    /// [`Options::set_skip_stats_update_on_db_open`] to be `true`. SST open
4446    /// errors are no longer returned by `DB::open`; they can instead surface as
4447    /// background errors or from operations that access the affected file.
4448    ///
4449    /// Default: `false`
4450    pub fn set_open_files_async(&mut self, enabled: bool) -> Result<(), Error> {
4451        let supported = unsafe {
4452            ffi::rust_rocksdb_options_set_open_files_async(self.inner, c_uchar::from(enabled)) != 0
4453        };
4454        if !supported {
4455            return Err(Error::new(
4456                "open_files_async requires RocksDB 11.1 or newer".to_owned(),
4457            ));
4458        }
4459        Ok(())
4460    }
4461
4462    /// Returns whether SST files are opened and validated in the background after open.
4463    pub fn get_open_files_async(&self) -> bool {
4464        unsafe { ffi::rust_rocksdb_options_get_open_files_async(self.inner) != 0 }
4465    }
4466
4467    /// Returns whether the linked RocksDB supports `open_files_async`.
4468    pub fn supports_open_files_async() -> bool {
4469        unsafe { ffi::rust_rocksdb_options_open_files_async_supported() != 0 }
4470    }
4471
4472    /// Specify the maximal number of info log files to be kept.
4473    ///
4474    /// Default: 1000
4475    ///
4476    /// # Examples
4477    ///
4478    /// ```
4479    /// use rust_rocksdb::Options;
4480    ///
4481    /// let mut options = Options::default();
4482    /// options.set_keep_log_file_num(100);
4483    /// ```
4484    pub fn set_keep_log_file_num(&mut self, nfiles: usize) {
4485        unsafe {
4486            ffi::rocksdb_options_set_keep_log_file_num(self.inner, nfiles);
4487        }
4488    }
4489
4490    /// Allow the OS to mmap file for writing.
4491    ///
4492    /// Default: false
4493    ///
4494    /// # Examples
4495    ///
4496    /// ```
4497    /// use rust_rocksdb::Options;
4498    ///
4499    /// let mut options = Options::default();
4500    /// options.set_allow_mmap_writes(true);
4501    /// ```
4502    pub fn set_allow_mmap_writes(&mut self, is_enabled: bool) {
4503        unsafe {
4504            ffi::rocksdb_options_set_allow_mmap_writes(self.inner, c_uchar::from(is_enabled));
4505        }
4506    }
4507
4508    /// Allow the OS to mmap file for reading sst tables.
4509    ///
4510    /// Default: false
4511    ///
4512    /// # Examples
4513    ///
4514    /// ```
4515    /// use rust_rocksdb::Options;
4516    ///
4517    /// let mut options = Options::default();
4518    /// options.set_allow_mmap_reads(true);
4519    /// ```
4520    pub fn set_allow_mmap_reads(&mut self, is_enabled: bool) {
4521        unsafe {
4522            ffi::rocksdb_options_set_allow_mmap_reads(self.inner, c_uchar::from(is_enabled));
4523        }
4524    }
4525
4526    /// If enabled, WAL is not flushed automatically after each write. Instead it
4527    /// relies on manual invocation of `DB::flush_wal()` to write the WAL buffer
4528    /// to its file.
4529    ///
4530    /// Default: false
4531    ///
4532    /// # Examples
4533    ///
4534    /// ```
4535    /// use rust_rocksdb::Options;
4536    ///
4537    /// let mut options = Options::default();
4538    /// options.set_manual_wal_flush(true);
4539    /// ```
4540    pub fn set_manual_wal_flush(&mut self, is_enabled: bool) {
4541        unsafe {
4542            ffi::rocksdb_options_set_manual_wal_flush(self.inner, c_uchar::from(is_enabled));
4543        }
4544    }
4545
4546    /// Guarantee that all column families are flushed together atomically.
4547    /// This option applies to both manual flushes (`db.flush()`) and automatic
4548    /// background flushes caused when memtables are filled.
4549    ///
4550    /// Note that this is only useful when the WAL is disabled. When using the
4551    /// WAL, writes are always consistent across column families.
4552    ///
4553    /// Default: false
4554    ///
4555    /// # Examples
4556    ///
4557    /// ```
4558    /// use rust_rocksdb::Options;
4559    ///
4560    /// let mut options = Options::default();
4561    /// options.set_atomic_flush(true);
4562    /// ```
4563    pub fn set_atomic_flush(&mut self, atomic_flush: bool) {
4564        unsafe {
4565            ffi::rocksdb_options_set_atomic_flush(self.inner, c_uchar::from(atomic_flush));
4566        }
4567    }
4568
4569    /// Sets global cache for table-level rows.
4570    ///
4571    /// Default: null (disabled)
4572    /// Not supported in ROCKSDB_LITE mode!
4573    pub fn set_row_cache(&mut self, cache: &Cache) {
4574        unsafe {
4575            ffi::rocksdb_options_set_row_cache(self.inner, cache.0.inner.as_ptr());
4576        }
4577        self.outlive.row_cache = Some(cache.clone());
4578    }
4579
4580    /// Use to control write rate of flush and compaction. Flush has higher
4581    /// priority than compaction.
4582    /// If rate limiter is enabled, bytes_per_sync is set to 1MB by default.
4583    ///
4584    /// Default: disable
4585    ///
4586    /// # Examples
4587    ///
4588    /// ```
4589    /// use rust_rocksdb::Options;
4590    ///
4591    /// let mut options = Options::default();
4592    /// options.set_ratelimiter(1024 * 1024, 100 * 1000, 10);
4593    /// ```
4594    pub fn set_ratelimiter(
4595        &mut self,
4596        rate_bytes_per_sec: i64,
4597        refill_period_us: i64,
4598        fairness: i32,
4599    ) {
4600        unsafe {
4601            let ratelimiter =
4602                ffi::rocksdb_ratelimiter_create(rate_bytes_per_sec, refill_period_us, fairness);
4603            ffi::rocksdb_options_set_ratelimiter(self.inner, ratelimiter);
4604            ffi::rocksdb_ratelimiter_destroy(ratelimiter);
4605        }
4606    }
4607
4608    /// Use to control write rate of flush and compaction. Flush has higher
4609    /// priority than compaction.
4610    /// If rate limiter is enabled, bytes_per_sync is set to 1MB by default.
4611    ///
4612    /// Default: disable
4613    pub fn set_auto_tuned_ratelimiter(
4614        &mut self,
4615        rate_bytes_per_sec: i64,
4616        refill_period_us: i64,
4617        fairness: i32,
4618    ) {
4619        unsafe {
4620            let ratelimiter = ffi::rocksdb_ratelimiter_create_auto_tuned(
4621                rate_bytes_per_sec,
4622                refill_period_us,
4623                fairness,
4624            );
4625            ffi::rocksdb_options_set_ratelimiter(self.inner, ratelimiter);
4626            ffi::rocksdb_ratelimiter_destroy(ratelimiter);
4627        }
4628    }
4629
4630    /// Create a RateLimiter object, which can be shared among RocksDB instances to
4631    /// control write rate of flush and compaction.
4632    ///
4633    /// rate_bytes_per_sec: this is the only parameter you want to set most of the
4634    /// time. It controls the total write rate of compaction and flush in bytes per
4635    /// second. Currently, RocksDB does not enforce rate limit for anything other
4636    /// than flush and compaction, e.g. write to WAL.
4637    ///
4638    /// refill_period_us: this controls how often tokens are refilled. For example,
4639    /// when rate_bytes_per_sec is set to 10MB/s and refill_period_us is set to
4640    /// 100ms, then 1MB is refilled every 100ms internally. Larger value can lead to
4641    /// burstier writes while smaller value introduces more CPU overhead.
4642    /// The default should work for most cases.
4643    ///
4644    /// fairness: RateLimiter accepts high-pri requests and low-pri requests.
4645    /// A low-pri request is usually blocked in favor of hi-pri request. Currently,
4646    /// RocksDB assigns low-pri to request from compaction and high-pri to request
4647    /// from flush. Low-pri requests can get blocked if flush requests come in
4648    /// continuously. This fairness parameter grants low-pri requests permission by
4649    /// 1/fairness chance even though high-pri requests exist to avoid starvation.
4650    /// You should be good by leaving it at default 10.
4651    ///
4652    /// mode: Mode indicates which types of operations count against the limit.
4653    ///
4654    /// auto_tuned: Enables dynamic adjustment of rate limit within the range
4655    ///              `[rate_bytes_per_sec / 20, rate_bytes_per_sec]`, according to
4656    ///              the recent demand for background I/O.
4657    pub fn set_ratelimiter_with_mode(
4658        &mut self,
4659        rate_bytes_per_sec: i64,
4660        refill_period_us: i64,
4661        fairness: i32,
4662        mode: RateLimiterMode,
4663        auto_tuned: bool,
4664    ) {
4665        unsafe {
4666            let ratelimiter = ffi::rocksdb_ratelimiter_create_with_mode(
4667                rate_bytes_per_sec,
4668                refill_period_us,
4669                fairness,
4670                mode as c_int,
4671                auto_tuned,
4672            );
4673            ffi::rocksdb_options_set_ratelimiter(self.inner, ratelimiter);
4674            ffi::rocksdb_ratelimiter_destroy(ratelimiter);
4675        }
4676    }
4677
4678    /// Sets the maximal size of the info log file.
4679    ///
4680    /// If the log file is larger than `max_log_file_size`, a new info log file
4681    /// will be created. If `max_log_file_size` is equal to zero, all logs will
4682    /// be written to one log file.
4683    ///
4684    /// Default: 0
4685    ///
4686    /// # Examples
4687    ///
4688    /// ```
4689    /// use rust_rocksdb::Options;
4690    ///
4691    /// let mut options = Options::default();
4692    /// options.set_max_log_file_size(0);
4693    /// ```
4694    pub fn set_max_log_file_size(&mut self, size: usize) {
4695        unsafe {
4696            ffi::rocksdb_options_set_max_log_file_size(self.inner, size);
4697        }
4698    }
4699
4700    /// Sets the time for the info log file to roll (in seconds).
4701    ///
4702    /// If specified with non-zero value, log file will be rolled
4703    /// if it has been active longer than `log_file_time_to_roll`.
4704    /// Default: 0 (disabled)
4705    pub fn set_log_file_time_to_roll(&mut self, secs: usize) {
4706        unsafe {
4707            ffi::rocksdb_options_set_log_file_time_to_roll(self.inner, secs);
4708        }
4709    }
4710
4711    /// Controls the recycling of log files.
4712    ///
4713    /// If non-zero, previously written log files will be reused for new logs,
4714    /// overwriting the old data. The value indicates how many such files we will
4715    /// keep around at any point in time for later use. This is more efficient
4716    /// because the blocks are already allocated and fdatasync does not need to
4717    /// update the inode after each write.
4718    ///
4719    /// Default: 0
4720    ///
4721    /// # Examples
4722    ///
4723    /// ```
4724    /// use rust_rocksdb::Options;
4725    ///
4726    /// let mut options = Options::default();
4727    /// options.set_recycle_log_file_num(5);
4728    /// ```
4729    pub fn set_recycle_log_file_num(&mut self, num: usize) {
4730        unsafe {
4731            ffi::rocksdb_options_set_recycle_log_file_num(self.inner, num);
4732        }
4733    }
4734
4735    /// Prints logs to stderr for faster debugging
4736    /// See official [wiki](https://github.com/facebook/rocksdb/wiki/Logger) for more information.
4737    pub fn set_stderr_logger(&mut self, log_level: LogLevel, prefix: impl CStrLike) {
4738        let p = prefix.into_c_string().unwrap();
4739
4740        unsafe {
4741            let logger = ffi::rocksdb_logger_create_stderr_logger(log_level as c_int, p.as_ptr());
4742            ffi::rocksdb_options_set_info_log(self.inner, logger);
4743            ffi::rocksdb_logger_destroy(logger);
4744        }
4745    }
4746
4747    /// Invokes `callback` with RocksDB log messages with level >= `log_level`.
4748    ///
4749    /// The callback can be called concurrently by multiple RocksDB threads.
4750    ///
4751    /// # Examples
4752    /// ```
4753    /// use rust_rocksdb::{LogLevel, Options};
4754    ///
4755    /// let mut options = Options::default();
4756    /// options.set_callback_logger(LogLevel::Debug, move |level, msg| println!("{level:?} {msg}"));
4757    /// ```
4758    pub fn set_callback_logger(
4759        &mut self,
4760        log_level: LogLevel,
4761        callback: impl Fn(LogLevel, &str) + 'static + Send + Sync,
4762    ) {
4763        // store the closure in an Arc so it can be shared across multiple Option/DBs
4764        let holder = Arc::new(LogCallback {
4765            callback: Box::new(callback),
4766        });
4767        let holder_ptr = std::ptr::from_ref::<LogCallback>(holder.as_ref());
4768        let holder_cvoid = holder_ptr.cast::<c_void>().cast_mut();
4769
4770        unsafe {
4771            let logger = ffi::rocksdb_logger_create_callback_logger(
4772                log_level as c_int,
4773                Some(Self::logger_callback),
4774                holder_cvoid,
4775            );
4776            ffi::rocksdb_options_set_info_log(self.inner, logger);
4777            ffi::rocksdb_logger_destroy(logger);
4778        }
4779
4780        self.outlive.log_callback = Some(holder);
4781    }
4782
4783    extern "C" fn logger_callback(func: *mut c_void, level: u32, msg: *mut c_char, len: usize) {
4784        use std::process;
4785
4786        // Neither argument can be trusted:
4787        //
4788        //  * `LogLevel` is `#[repr(i32)]`, and `level` is whatever
4789        //    `InfoLogLevel` the C layer cast to an unsigned, so transmuting it
4790        //    could materialise an invalid discriminant.
4791        //  * `msg` is raw `vsnprintf` output. Log lines routinely embed
4792        //    filesystem paths and `Status::ToString()` text, and paths reach
4793        //    RocksDB via `OsStr::as_bytes()`, which is not UTF-8 validated, so
4794        //    `from_utf8_unchecked` was unsound.
4795        //
4796        // `from_utf8_lossy` returns `Cow::Borrowed` for valid UTF-8, so the
4797        // common path still does not allocate.
4798        let level = LogLevel::try_from_raw(level as i32).unwrap_or(LogLevel::Info);
4799        let slice = if len == 0 {
4800            &[][..]
4801        } else {
4802            unsafe { slice::from_raw_parts(msg.cast_const().cast::<u8>(), len) }
4803        };
4804        let msg = String::from_utf8_lossy(slice);
4805
4806        // Shared reference, not `&mut`: RocksDB logs from several background
4807        // threads at once, so a `&mut` here would alias. `LogCallbackFn` is a
4808        // `dyn Fn`, so a shared reference is all it needs.
4809        let holder = unsafe { &*func.cast::<LogCallback>() };
4810        let callback_in_catch_unwind = AssertUnwindSafe(&holder.callback);
4811        if catch_unwind(move || callback_in_catch_unwind(level, &msg)).is_err() {
4812            process::abort();
4813        }
4814    }
4815
4816    /// Sets the threshold at which all writes will be slowed down to at least delayed_write_rate if estimated
4817    /// bytes needed to be compaction exceed this threshold.
4818    ///
4819    /// Default: 64GB
4820    pub fn set_soft_pending_compaction_bytes_limit(&mut self, limit: usize) {
4821        unsafe {
4822            ffi::rocksdb_options_set_soft_pending_compaction_bytes_limit(self.inner, limit);
4823        }
4824    }
4825
4826    /// Sets the bytes threshold at which all writes are stopped if estimated bytes needed to be compaction exceed
4827    /// this threshold.
4828    ///
4829    /// Default: 256GB
4830    pub fn set_hard_pending_compaction_bytes_limit(&mut self, limit: usize) {
4831        unsafe {
4832            ffi::rocksdb_options_set_hard_pending_compaction_bytes_limit(self.inner, limit);
4833        }
4834    }
4835
4836    /// Sets the size of one block in arena memory allocation.
4837    ///
4838    /// If <= 0, a proper value is automatically calculated (usually 1/10 of
4839    /// writer_buffer_size).
4840    ///
4841    /// Default: 0
4842    pub fn set_arena_block_size(&mut self, size: usize) {
4843        unsafe {
4844            ffi::rocksdb_options_set_arena_block_size(self.inner, size);
4845        }
4846    }
4847
4848    /// If true, then print malloc stats together with rocksdb.stats when printing to LOG.
4849    ///
4850    /// Default: false
4851    pub fn set_dump_malloc_stats(&mut self, enabled: bool) {
4852        unsafe {
4853            ffi::rocksdb_options_set_dump_malloc_stats(self.inner, c_uchar::from(enabled));
4854        }
4855    }
4856
4857    /// Enable whole key bloom filter in memtable. Note this will only take effect
4858    /// if memtable_prefix_bloom_size_ratio is not 0. Enabling whole key filtering
4859    /// can potentially reduce CPU usage for point-look-ups.
4860    ///
4861    /// Default: false (disable)
4862    ///
4863    /// Dynamically changeable through SetOptions() API
4864    pub fn set_memtable_whole_key_filtering(&mut self, whole_key_filter: bool) {
4865        unsafe {
4866            ffi::rocksdb_options_set_memtable_whole_key_filtering(
4867                self.inner,
4868                c_uchar::from(whole_key_filter),
4869            );
4870        }
4871    }
4872
4873    /// Enable the use of key-value separation.
4874    ///
4875    /// More details can be found here: [Integrated BlobDB](http://rocksdb.org/blog/2021/05/26/integrated-blob-db.html).
4876    ///
4877    /// Default: false (disable)
4878    ///
4879    /// Dynamically changeable through SetOptions() API
4880    pub fn set_enable_blob_files(&mut self, val: bool) {
4881        unsafe {
4882            ffi::rocksdb_options_set_enable_blob_files(self.inner, u8::from(val));
4883        }
4884    }
4885
4886    /// Sets the minimum threshold value at or above which will be written
4887    /// to blob files during flush or compaction.
4888    ///
4889    /// Dynamically changeable through SetOptions() API
4890    pub fn set_min_blob_size(&mut self, val: u64) {
4891        unsafe {
4892            ffi::rocksdb_options_set_min_blob_size(self.inner, val);
4893        }
4894    }
4895
4896    /// Sets the size limit for blob files.
4897    ///
4898    /// Dynamically changeable through SetOptions() API
4899    pub fn set_blob_file_size(&mut self, val: u64) {
4900        unsafe {
4901            ffi::rocksdb_options_set_blob_file_size(self.inner, val);
4902        }
4903    }
4904
4905    /// Sets the blob compression type. All blob files use the same
4906    /// compression type.
4907    ///
4908    /// Dynamically changeable through SetOptions() API
4909    pub fn set_blob_compression_type(&mut self, val: DBCompressionType) {
4910        unsafe {
4911            ffi::rocksdb_options_set_blob_compression_type(self.inner, val as _);
4912        }
4913    }
4914
4915    /// The compression algorithm used for blob files.
4916    ///
4917    /// `None` covers a compression type this crate does not name.
4918    pub fn get_blob_compression_type(&self) -> Option<DBCompressionType> {
4919        let raw = unsafe { ffi::rocksdb_options_get_blob_compression_type(self.inner) };
4920        DBCompressionType::try_from_raw(raw)
4921    }
4922
4923    /// If this is set to true RocksDB will actively relocate valid blobs from the oldest blob files
4924    /// as they are encountered during compaction.
4925    ///
4926    /// Dynamically changeable through SetOptions() API
4927    pub fn set_enable_blob_gc(&mut self, val: bool) {
4928        unsafe {
4929            ffi::rocksdb_options_set_enable_blob_gc(self.inner, u8::from(val));
4930        }
4931    }
4932
4933    /// Sets the threshold that the GC logic uses to determine which blob files should be considered “old.”
4934    ///
4935    /// For example, the default value of 0.25 signals to RocksDB that blobs residing in the
4936    /// oldest 25% of blob files should be relocated by GC. This parameter can be tuned to adjust
4937    /// the trade-off between write amplification and space amplification.
4938    ///
4939    /// Dynamically changeable through SetOptions() API
4940    pub fn set_blob_gc_age_cutoff(&mut self, val: c_double) {
4941        unsafe {
4942            ffi::rocksdb_options_set_blob_gc_age_cutoff(self.inner, val);
4943        }
4944    }
4945
4946    /// Sets the blob GC force threshold.
4947    ///
4948    /// Dynamically changeable through SetOptions() API
4949    pub fn set_blob_gc_force_threshold(&mut self, val: c_double) {
4950        unsafe {
4951            ffi::rocksdb_options_set_blob_gc_force_threshold(self.inner, val);
4952        }
4953    }
4954
4955    /// Sets the blob compaction read ahead size.
4956    ///
4957    /// Dynamically changeable through SetOptions() API
4958    pub fn set_blob_compaction_readahead_size(&mut self, val: u64) {
4959        unsafe {
4960            ffi::rocksdb_options_set_blob_compaction_readahead_size(self.inner, val);
4961        }
4962    }
4963
4964    /// Sets the blob cache.
4965    ///
4966    /// Using a dedicated object for blobs and using the same object for the block and blob caches
4967    /// are both supported. In the latter case, note that blobs are less valuable from a caching
4968    /// perspective than SST blocks, and some cache implementations have configuration options that
4969    /// can be used to prioritize items accordingly (see Cache::Priority and
4970    /// LRUCacheOptions::{high,low}_pri_pool_ratio).
4971    ///
4972    /// Default: disabled
4973    pub fn set_blob_cache(&mut self, cache: &Cache) {
4974        unsafe {
4975            ffi::rocksdb_options_set_blob_cache(self.inner, cache.0.inner.as_ptr());
4976        }
4977        self.outlive.blob_cache = Some(cache.clone());
4978    }
4979
4980    /// Whether newly written blobs go straight into the blob cache.
4981    ///
4982    /// [`PrepopulateBlobCache::FlushOnly`] pays off when reading a blob back is expensive,
4983    /// with direct I/O or remote storage, or when the workload has strong temporal locality.
4984    /// It needs [`Self::set_blob_cache`] to have been called to have any effect.
4985    ///
4986    /// Default: [`PrepopulateBlobCache::Disable`]
4987    ///
4988    /// Dynamically changeable through SetOptions() API
4989    pub fn set_prepopulate_blob_cache(&mut self, val: PrepopulateBlobCache) {
4990        unsafe {
4991            ffi::rocksdb_options_set_prepopulate_blob_cache(self.inner, val as c_int);
4992        }
4993    }
4994
4995    /// The setting from [`Self::set_prepopulate_blob_cache`].
4996    ///
4997    /// `None` covers a value this crate does not name, which RocksDB has none of today.
4998    pub fn get_prepopulate_blob_cache(&self) -> Option<PrepopulateBlobCache> {
4999        let raw = unsafe { ffi::rocksdb_options_get_prepopulate_blob_cache(self.inner) };
5000        PrepopulateBlobCache::try_from_raw(raw)
5001    }
5002
5003    /// Set this option to true during creation of database if you want
5004    /// to be able to ingest behind (call IngestExternalFile() skipping keys
5005    /// that already exist, rather than overwriting matching keys).
5006    /// Setting this option to true has the following effects:
5007    ///
5008    /// 1. Disable some internal optimizations around SST file compression.
5009    /// 2. Reserve the last level for ingested files only.
5010    /// 3. Compaction will not include any file from the last level.
5011    ///
5012    /// Note that only Universal Compaction supports allow_ingest_behind.
5013    /// `num_levels` should be >= 3 if this option is turned on.
5014    ///
5015    /// DEFAULT: false
5016    /// Immutable.
5017    pub fn set_allow_ingest_behind(&mut self, val: bool) {
5018        unsafe {
5019            ffi::rocksdb_options_set_allow_ingest_behind(self.inner, c_uchar::from(val));
5020        }
5021    }
5022
5023    // A factory of a table property collector that marks an SST
5024    // file as need-compaction when it observe at least "D" deletion
5025    // entries in any "N" consecutive entries, or the ratio of tombstone
5026    // entries >= deletion_ratio.
5027    //
5028    // `window_size`: is the sliding window size "N"
5029    // `num_dels_trigger`: is the deletion trigger "D"
5030    // `deletion_ratio`: if <= 0 or > 1, disable triggering compaction based on
5031    // deletion ratio.
5032    pub fn add_compact_on_deletion_collector_factory(
5033        &mut self,
5034        window_size: size_t,
5035        num_dels_trigger: size_t,
5036        deletion_ratio: f64,
5037    ) {
5038        unsafe {
5039            ffi::rocksdb_options_add_compact_on_deletion_collector_factory_del_ratio(
5040                self.inner,
5041                window_size,
5042                num_dels_trigger,
5043                deletion_ratio,
5044            );
5045        }
5046    }
5047
5048    /// Like [`Self::add_compact_on_deletion_collector_factory`], but with the ratio trigger
5049    /// off, so a file is only marked once `num_dels_trigger` deletions land inside a window
5050    /// of `window_size` consecutive entries.
5051    ///
5052    /// `window_size` is rounded up to a multiple of 128. `num_dels_trigger` is used as given
5053    /// and is not rescaled when `window_size` changes.
5054    ///
5055    /// This appends another collector factory to the column family's list, it does not
5056    /// replace the ones already there. Calling it twice registers the collector twice.
5057    pub fn add_compact_on_deletion_collector_factory_count_only(
5058        &mut self,
5059        window_size: size_t,
5060        num_dels_trigger: size_t,
5061    ) {
5062        unsafe {
5063            ffi::rocksdb_options_add_compact_on_deletion_collector_factory(
5064                self.inner,
5065                window_size,
5066                num_dels_trigger,
5067            );
5068        }
5069    }
5070
5071    /// Like [`Self::add_compact_on_deletion_collector_factory`], but only triggers
5072    /// compaction if the SST file size is at least `min_file_size` bytes.
5073    pub fn add_compact_on_deletion_collector_factory_min_file_size(
5074        &mut self,
5075        window_size: size_t,
5076        num_dels_trigger: size_t,
5077        deletion_ratio: f64,
5078        min_file_size: u64,
5079    ) {
5080        unsafe {
5081            ffi::rocksdb_options_add_compact_on_deletion_collector_factory_min_file_size(
5082                self.inner,
5083                window_size,
5084                num_dels_trigger,
5085                deletion_ratio,
5086                min_file_size,
5087            );
5088        }
5089    }
5090
5091    /// <https://github.com/facebook/rocksdb/wiki/Write-Buffer-Manager>
5092    /// Write buffer manager helps users control the total memory used by memtables across multiple column families and/or DB instances.
5093    /// Users can enable this control by 2 ways:
5094    ///
5095    /// 1- Limit the total memtable usage across multiple column families and DBs under a threshold.
5096    /// 2- Cost the memtable memory usage to block cache so that memory of RocksDB can be capped by the single limit.
5097    /// The usage of a write buffer manager is similar to rate_limiter and sst_file_manager.
5098    /// 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.
5099    pub fn set_write_buffer_manager(&mut self, write_buffer_manager: &WriteBufferManager) {
5100        unsafe {
5101            ffi::rocksdb_options_set_write_buffer_manager(
5102                self.inner,
5103                write_buffer_manager.0.inner.as_ptr(),
5104            );
5105        }
5106        self.outlive.write_buffer_manager = Some(write_buffer_manager.clone());
5107    }
5108
5109    /// Sets an `SstFileManager` for this `Options`.
5110    ///
5111    /// SstFileManager tracks and controls total SST file space usage, enabling
5112    /// applications to cap disk utilization and throttle deletions.
5113    pub fn set_sst_file_manager(&mut self, sst_file_manager: &SstFileManager) {
5114        unsafe {
5115            ffi::rocksdb_options_set_sst_file_manager(
5116                self.inner,
5117                sst_file_manager.0.inner.as_ptr(),
5118            );
5119        }
5120        self.outlive.sst_file_manager = Some(sst_file_manager.clone());
5121    }
5122
5123    /// If true, working thread may avoid doing unnecessary and long-latency
5124    /// operation (such as deleting obsolete files directly or deleting memtable)
5125    /// and will instead schedule a background job to do it.
5126    ///
5127    /// Use it if you're latency-sensitive.
5128    ///
5129    /// Default: false (disabled)
5130    pub fn set_avoid_unnecessary_blocking_io(&mut self, val: bool) {
5131        unsafe {
5132            ffi::rocksdb_options_set_avoid_unnecessary_blocking_io(self.inner, u8::from(val));
5133        }
5134    }
5135
5136    /// Activates the experimental Mempurge memtable garbage collection feature.
5137    ///
5138    /// See the upstream RocksDB option documentation:
5139    /// <https://github.com/facebook/rocksdb/blob/v10.7.5/include/rocksdb/advanced_options.h#L259-L274>
5140    ///
5141    /// At every flush, RocksDB estimates the useful payload ratio of the memtable
5142    /// and compares it with this threshold. If the ratio is below the threshold,
5143    /// RocksDB replaces the regular flush with a mempurge operation.
5144    ///
5145    /// Threshold values:
5146    ///
5147    /// * `0.0`: mempurge deactivated.
5148    /// * `1.0`: recommended threshold value.
5149    /// * `> 1.0`: aggressive mempurge.
5150    /// * `0.0 < threshold < 1.0`: mempurge only for very low useful payload ratios.
5151    ///
5152    /// Default: 0.0
5153    pub fn set_experimental_mempurge_threshold(&mut self, threshold: f64) {
5154        unsafe {
5155            ffi::rocksdb_options_set_experimental_mempurge_threshold(self.inner, threshold);
5156        }
5157    }
5158
5159    /// Sets the compaction priority.
5160    ///
5161    /// If level compaction_style =
5162    /// kCompactionStyleLevel, for each level, which files are prioritized to be
5163    /// picked to compact.
5164    ///
5165    /// Default: `DBCompactionPri::MinOverlappingRatio`
5166    ///
5167    /// # Examples
5168    ///
5169    /// ```
5170    /// use rust_rocksdb::{Options, DBCompactionPri};
5171    ///
5172    /// let mut opts = Options::default();
5173    /// opts.set_compaction_pri(DBCompactionPri::RoundRobin);
5174    /// ```
5175    pub fn set_compaction_pri(&mut self, pri: DBCompactionPri) {
5176        unsafe {
5177            ffi::rocksdb_options_set_compaction_pri(self.inner, pri as c_int);
5178        }
5179    }
5180
5181    /// The file pick order set by [`Self::set_compaction_pri`].
5182    ///
5183    /// [`DBCompactionPri`] covers every value RocksDB defines today, so `None` only shows up
5184    /// if a future release adds one.
5185    pub fn get_compaction_pri(&self) -> Option<DBCompactionPri> {
5186        let raw = unsafe { ffi::rocksdb_options_get_compaction_pri(self.inner) };
5187        DBCompactionPri::try_from_raw(raw)
5188    }
5189
5190    /// If true, the log numbers and sizes of the synced WALs are tracked
5191    /// in MANIFEST. During DB recovery, if a synced WAL is missing
5192    /// from disk, or the WAL's size does not match the recorded size in
5193    /// MANIFEST, an error will be reported and the recovery will be aborted.
5194    ///
5195    /// This is one additional protection against WAL corruption besides the
5196    /// per-WAL-entry checksum.
5197    ///
5198    /// Note that this option does not work with secondary instance.
5199    /// Currently, only syncing closed WALs are tracked. Calling `DB::SyncWAL()`,
5200    /// etc. or writing with `WriteOptions::sync=true` to sync the live WAL is not
5201    /// tracked for performance/efficiency reasons.
5202    ///
5203    /// See: <https://github.com/facebook/rocksdb/wiki/Track-WAL-in-MANIFEST>
5204    ///
5205    /// Default: false (disabled)
5206    pub fn set_track_and_verify_wals_in_manifest(&mut self, val: bool) {
5207        unsafe {
5208            ffi::rocksdb_options_set_track_and_verify_wals_in_manifest(self.inner, u8::from(val));
5209        }
5210    }
5211
5212    /// Returns the value of the `track_and_verify_wals_in_manifest` option.
5213    pub fn get_track_and_verify_wals_in_manifest(&self) -> bool {
5214        let val_u8 =
5215            unsafe { ffi::rocksdb_options_get_track_and_verify_wals_in_manifest(self.inner) };
5216        val_u8 != 0
5217    }
5218
5219    /// The DB unique ID can be saved in the DB manifest (preferred, this option)
5220    /// or an IDENTITY file (historical, deprecated), or both. If this option is
5221    /// set to false (old behavior), then `write_identity_file` must be set to true.
5222    /// The manifest is preferred because
5223    ///
5224    /// 1. The IDENTITY file is not checksummed, so it is not as safe against
5225    ///    corruption.
5226    /// 2. The IDENTITY file may or may not be copied with the DB (e.g. not
5227    ///    copied by BackupEngine), so is not reliable for the provenance of a DB.
5228    ///
5229    /// This option might eventually be obsolete and removed as Identity files
5230    /// are phased out.
5231    ///
5232    /// Default: true (enabled)
5233    pub fn set_write_dbid_to_manifest(&mut self, val: bool) {
5234        unsafe {
5235            ffi::rocksdb_options_set_write_dbid_to_manifest(self.inner, u8::from(val));
5236        }
5237    }
5238
5239    /// Returns the value of the `write_dbid_to_manifest` option.
5240    pub fn get_write_dbid_to_manifest(&self) -> bool {
5241        let val_u8 = unsafe { ffi::rocksdb_options_get_write_dbid_to_manifest(self.inner) };
5242        val_u8 != 0
5243    }
5244
5245    /// Sets the logger to use.
5246    ///
5247    /// By default `rocksdb` writes its internal logs to a file in the database
5248    /// directory; this can be changed to a custom callback with the
5249    /// [`InfoLogger::new_callback_logger`] constructor.
5250    pub fn set_info_logger(&mut self, mut logger: InfoLogger) {
5251        // Move the callback so it can be shared across database instances
5252        self.outlive.logger_callback = logger.callback.take();
5253        unsafe {
5254            ffi::rocksdb_options_set_info_log(self.inner, logger.inner);
5255        }
5256    }
5257
5258    /// Returns a reference to the currently configured logger.
5259    pub fn get_info_logger(&self) -> InfoLogger {
5260        let raw = unsafe { ffi::rocksdb_options_get_info_log(self.inner) };
5261        InfoLogger {
5262            inner: raw,
5263            callback: self.outlive.logger_callback.clone(),
5264        }
5265    }
5266
5267    /// Sets the `add` option.
5268    pub fn set_add(&mut self, val: c_int) {
5269        unsafe {
5270            ffi::rocksdb_options_calculate_sst_write_lifetime_hint_set_add(self.inner, val);
5271        }
5272    }
5273
5274    /// Empties the set of compaction styles that get SST write lifetime hints.
5275    ///
5276    /// The hints tell the filesystem how long a file is expected to live, which cuts write
5277    /// amplification from OS level garbage collection and SSD wear levelling. RocksDB derives
5278    /// them from the output level alone, so a workload whose data lifetime varies a lot
5279    /// inside one level can end up worse off. Clearing the set is the documented way to turn
5280    /// the feature off. The default set holds level compaction only.
5281    ///
5282    /// Entries go in through [`Self::set_add`] and come back out through
5283    /// [`Self::set_remove`], both of which take the raw `rocksdb::CompactionStyle` value.
5284    pub fn clear_calculate_sst_write_lifetime_hint_set(&mut self) {
5285        unsafe {
5286            ffi::rocksdb_options_calculate_sst_write_lifetime_hint_set_clear(self.inner);
5287        }
5288    }
5289
5290    /// Whether `style` is in the set of compaction styles that get SST write lifetime hints.
5291    ///
5292    /// Only level and universal compaction do anything with the hints, even when another
5293    /// style is in the set. See [`Self::clear_calculate_sst_write_lifetime_hint_set`].
5294    pub fn calculate_sst_write_lifetime_hint_set_contains(&self, style: DBCompactionStyle) -> bool {
5295        unsafe {
5296            ffi::rocksdb_options_calculate_sst_write_lifetime_hint_set_contains(
5297                self.inner,
5298                style as c_int,
5299            ) != 0
5300        }
5301    }
5302
5303    /// How many compaction styles are in the SST write lifetime hint set.
5304    ///
5305    /// See [`Self::clear_calculate_sst_write_lifetime_hint_set`].
5306    pub fn calculate_sst_write_lifetime_hint_set_count(&self) -> usize {
5307        unsafe { ffi::rocksdb_options_calculate_sst_write_lifetime_hint_set_count(self.inner) }
5308    }
5309
5310    /// if set to false then recovery will fail when a prepared transaction is encountered in
5311    /// the WAL
5312    pub fn set_allow_2pc(&mut self, val: bool) {
5313        unsafe {
5314            ffi::rocksdb_options_set_allow_2pc(self.inner, c_uchar::from(val));
5315        }
5316    }
5317
5318    /// Returns the value of the `allow_2pc` option.
5319    pub fn get_allow_2pc(&self) -> bool {
5320        unsafe { ffi::rocksdb_options_get_allow_2pc(self.inner) != 0 }
5321    }
5322
5323    /// It allows user to opt-in to get error messages containing corrupted keys/values.
5324    /// Corrupt keys, values will be logged in the messages/logs/status that will help users
5325    /// with the useful information regarding affected data. By default value is set false to
5326    /// prevent users data to be exposed in the logs/messages etc.
5327    ///
5328    /// Default: false
5329    pub fn set_allow_data_in_errors(&mut self, val: bool) {
5330        unsafe {
5331            ffi::rocksdb_options_set_allow_data_in_errors(self.inner, c_uchar::from(val));
5332        }
5333    }
5334
5335    /// Returns the value of the `allow_data_in_errors` option.
5336    pub fn get_allow_data_in_errors(&self) -> bool {
5337        unsafe { ffi::rocksdb_options_get_allow_data_in_errors(self.inner) != 0 }
5338    }
5339
5340    /// If false, fallocate() calls are bypassed, which disables file preallocation. The file
5341    /// space preallocation is used to increase the file write/append performance. By default,
5342    /// RocksDB preallocates space for WAL, SST, Manifest files, the extra space is truncated
5343    /// when the file is written. Warning: if you're using btrfs, we would recommend setting
5344    /// `allow_fallocate=false` to disable preallocation. As on btrfs, the extra allocated
5345    /// space cannot be freed, which could be significant if you have lots of files. More
5346    /// details about this limitation:
5347    /// <https://github.com/btrfs/btrfs-dev-docs/blob/471c5699336e043114d4bca02adcd57d9dab9c44/data-extent-reference-counts.md>
5348    pub fn set_allow_fallocate(&mut self, val: bool) {
5349        unsafe {
5350            ffi::rocksdb_options_set_allow_fallocate(self.inner, c_uchar::from(val));
5351        }
5352    }
5353
5354    /// Returns the value of the `allow_fallocate` option.
5355    pub fn get_allow_fallocate(&self) -> bool {
5356        unsafe { ffi::rocksdb_options_get_allow_fallocate(self.inner) != 0 }
5357    }
5358
5359    /// EXPERIMENTAL: If true, RocksDB asynchronously precreates the next WAL file so
5360    /// foreground memtable switching can usually avoid the filesystem latency of creating a
5361    /// new WAL. The precreated file is only reserved empty storage; it does not become a
5362    /// logical WAL and is not added to WAL tracking until it is consumed by a foreground WAL
5363    /// rotation.
5364    ///
5365    /// The option is sanitized to false when recycle_log_file_num is non-zero.
5366    ///
5367    /// Default: false
5368    pub fn set_async_wal_precreate(&mut self, val: bool) {
5369        unsafe {
5370            ffi::rocksdb_options_set_async_wal_precreate(self.inner, c_uchar::from(val));
5371        }
5372    }
5373
5374    /// Returns the value of the `async_wal_precreate` option.
5375    pub fn get_async_wal_precreate(&self) -> bool {
5376        unsafe { ffi::rocksdb_options_get_async_wal_precreate(self.inner) != 0 }
5377    }
5378
5379    /// By default RocksDB replay WAL logs and flush them on DB open, which may create very
5380    /// small SST files. If this option is enabled, RocksDB will try to avoid (but not
5381    /// guarantee not to) flush during recovery. Also, existing WAL logs will be kept, so that
5382    /// if crash happened before flush, we still have logs to recover from.
5383    ///
5384    /// Note: when `enforce_write_buffer_manager_during_recovery` is also enabled, flushes may
5385    /// still occur during recovery to respect the WriteBufferManager's global memory limit,
5386    /// even if this option is true. Once any such WBM-triggered flush happens, all remaining
5387    /// memtables will also be flushed at the end of recovery (similar to the behavior when
5388    /// this option is false).
5389    ///
5390    /// DEFAULT: false
5391    pub fn set_avoid_flush_during_recovery(&mut self, val: bool) {
5392        unsafe {
5393            ffi::rocksdb_options_set_avoid_flush_during_recovery(self.inner, c_uchar::from(val));
5394        }
5395    }
5396
5397    /// Returns the value of the `avoid_flush_during_recovery` option.
5398    pub fn get_avoid_flush_during_recovery(&self) -> bool {
5399        unsafe { ffi::rocksdb_options_get_avoid_flush_during_recovery(self.inner) != 0 }
5400    }
5401
5402    /// By default RocksDB will flush all memtables on DB close if there are unpersisted data
5403    /// (i.e. with WAL disabled) The flush can be skip to speedup DB close. Unpersisted data
5404    /// WILL BE LOST.
5405    ///
5406    /// DEFAULT: false
5407    ///
5408    /// Dynamically changeable through SetDBOptions() API.
5409    pub fn set_avoid_flush_during_shutdown(&mut self, val: bool) {
5410        unsafe {
5411            ffi::rocksdb_options_set_avoid_flush_during_shutdown(self.inner, c_uchar::from(val));
5412        }
5413    }
5414
5415    /// Returns the value of the `avoid_flush_during_shutdown` option.
5416    pub fn get_avoid_flush_during_shutdown(&self) -> bool {
5417        unsafe { ffi::rocksdb_options_get_avoid_flush_during_shutdown(self.inner) != 0 }
5418    }
5419
5420    /// Set to true to re-instate an old behavior of keeping complete, synced WAL files open
5421    /// for write until they are collected for deletion by a background thread. This should
5422    /// not be needed unless there is a performance issue with file Close(), but setting it to
5423    /// true means that Checkpoint might call LinkFile on a WAL still open for write, which
5424    /// might be unsupported on some FileSystem implementations. As this is intended as a
5425    /// temporary kill switch, it is already DEPRECATED.
5426    pub fn set_background_close_inactive_wals(&mut self, val: bool) {
5427        unsafe {
5428            ffi::rocksdb_options_set_background_close_inactive_wals(self.inner, c_uchar::from(val));
5429        }
5430    }
5431
5432    /// Returns the value of the `background_close_inactive_wals` option.
5433    pub fn get_background_close_inactive_wals(&self) -> bool {
5434        unsafe { ffi::rocksdb_options_get_background_close_inactive_wals(self.inner) != 0 }
5435    }
5436
5437    /// By default, RocksDB will attempt to detect any data losses or corruptions in DB files
5438    /// and return an error to the user, either at DB::Open time or later during DB operation.
5439    /// The exception to this policy is the WAL file, whose recovery is controlled by the
5440    /// wal_recovery_mode option.
5441    ///
5442    /// Best-efforts recovery (this option set to true) signals a preference for opening the
5443    /// DB to any point-in-time valid state for each column family, including the empty/new
5444    /// state, versus the default of returning non-WAL data losses to the user as errors. In
5445    /// terms of RocksDB user data, this is like applying
5446    /// WALRecoveryMode::kPointInTimeRecovery to each column family rather than just the WAL.
5447    ///
5448    /// The behavior changes in the presence of "AtomicGroup"s in the MANIFEST, which is
5449    /// currently only the case when `atomic_flush == true`. In that case, all pre-existing
5450    /// CFs must recover the atomic group in order for that group to be applied in an
5451    /// all-or-nothing manner. This means that unused/inactive CF(s) with invalid filesystem
5452    /// state can block recovery of all other CFs at an atomic group.
5453    ///
5454    /// Best-efforts recovery (BER) is specifically designed to recover a DB with files that
5455    /// are missing or truncated to some smaller size, such as the result of an incomplete DB
5456    /// "physical" (FileSystem) copy. BER can also detect when an SST file has been replaced
5457    /// with a different one of the same size (assuming SST unique IDs are tracked in DB
5458    /// manifest). BER is not yet designed to produce a usable DB from other corruptions to DB
5459    /// files (which should generally be detectable by DB::VerifyChecksum()), and BER does not
5460    /// yet attempt to recover any WAL files.
5461    ///
5462    /// For example, if an SST or blob file referenced by the MANIFEST is missing, BER might
5463    /// be able to find a set of files corresponding to an old "point in time" version of the
5464    /// column family, possibly from an older MANIFEST file. Besides complete "point in time"
5465    /// version, an incomplete version with only a suffix of L0 files missing can also be
5466    /// recovered to if the versioning history doesn't include an atomic flush.  From the
5467    /// users' perspective, missing a suffix of L0 files means missing the user's most
5468    /// recently written data. So the remaining available files still presents a valid point
5469    /// in time view, although for some previous time. It's not done for atomic flush because
5470    /// that guarantees a consistent view across column families. We cannot guarantee that if
5471    /// recovering an incomplete version. Some other kinds of DB files (e.g. CURRENT, LOCK,
5472    /// IDENTITY) are either ignored or replaced with BER, or quietly fixed regardless of BER
5473    /// setting. BER does require at least one valid MANIFEST to recover to a non-trivial DB
5474    /// state, unlike `ldb repair`.
5475    ///
5476    /// Default: false
5477    pub fn set_best_efforts_recovery(&mut self, val: bool) {
5478        unsafe {
5479            ffi::rocksdb_options_set_best_efforts_recovery(self.inner, c_uchar::from(val));
5480        }
5481    }
5482
5483    /// Returns the value of the `best_efforts_recovery` option.
5484    pub fn get_best_efforts_recovery(&self) -> bool {
5485        unsafe { ffi::rocksdb_options_get_best_efforts_recovery(self.inner) != 0 }
5486    }
5487
5488    /// If max_bgerror_resume_count is >= 2, db resume is called multiple times. This option
5489    /// decides how long to wait to retry the next resume if the previous resume fails and
5490    /// satisfy redo resume conditions.
5491    ///
5492    /// Default: 1000000 (microseconds).
5493    pub fn set_bgerror_resume_retry_interval(&mut self, val: u64) {
5494        unsafe {
5495            ffi::rocksdb_options_set_bgerror_resume_retry_interval(self.inner, val);
5496        }
5497    }
5498
5499    /// Returns the value of the `bgerror_resume_retry_interval` option.
5500    pub fn get_bgerror_resume_retry_interval(&self) -> u64 {
5501        unsafe { ffi::rocksdb_options_get_bgerror_resume_retry_interval(self.inner) }
5502    }
5503
5504    /// Number of direct-write blob partitions for this column family. Requires
5505    /// enable_blob_direct_write = true.
5506    ///
5507    /// If blob_direct_write_partition_strategy is null, partition selection uses the default
5508    /// round-robin strategy.
5509    ///
5510    /// Default: 1
5511    ///
5512    /// Not dynamically changeable through the SetOptions() API.
5513    pub fn set_blob_direct_write_partitions(&mut self, val: u32) {
5514        unsafe {
5515            ffi::rocksdb_options_set_blob_direct_write_partitions(self.inner, val);
5516        }
5517    }
5518
5519    /// Returns the value of the `blob_direct_write_partitions` option.
5520    pub fn get_blob_direct_write_partitions(&self) -> u32 {
5521        unsafe { ffi::rocksdb_options_get_blob_direct_write_partitions(self.inner) }
5522    }
5523
5524    /// Enable/disable per key-value checksum protection for in memory blocks.
5525    ///
5526    /// Checksum is constructed when a block is loaded into memory and verification is done
5527    /// for each key read from the block. This is useful for detecting in-memory data
5528    /// corruption. Note that this feature has a non-trivial negative impact on read
5529    /// performance. Different values of the option have similar performance impact, but
5530    /// different memory cost and corruption detection probability (e.g. 1 byte gives 255/256
5531    /// chance for detecting a corruption).
5532    ///
5533    /// Default: 0 (no protection) Supported values: 0, 1, 2, 4, 8. Dynamically changeable
5534    /// through the SetOptions() API.
5535    pub fn set_block_protection_bytes_per_key(&mut self, val: u8) {
5536        unsafe {
5537            ffi::rocksdb_options_set_block_protection_bytes_per_key(self.inner, val);
5538        }
5539    }
5540
5541    /// Returns the value of the `block_protection_bytes_per_key` option.
5542    pub fn get_block_protection_bytes_per_key(&self) -> u8 {
5543        unsafe { ffi::rocksdb_options_get_block_protection_bytes_per_key(self.inner) }
5544    }
5545
5546    /// For leveled compaction, RocksDB may compact a file at the bottommost level if it can
5547    /// compact away data that were protected by some snapshot. The compaction reason in LOG
5548    /// for this kind of compactions is "BottommostFiles". Usually such compaction can happen
5549    /// as soon as a relevant snapshot is released. This option allows user to delay such
5550    /// compactions. A file is qualified for "BottommostFiles" compaction if it is at least
5551    /// "bottommost_file_compaction_delay" seconds old.
5552    ///
5553    /// Default: 0 (no delay) Dynamically changeable through the SetOptions() API.
5554    pub fn set_bottommost_file_compaction_delay(&mut self, val: u32) {
5555        unsafe {
5556            ffi::rocksdb_options_set_bottommost_file_compaction_delay(self.inner, val);
5557        }
5558    }
5559
5560    /// Returns the value of the `bottommost_file_compaction_delay` option.
5561    pub fn get_bottommost_file_compaction_delay(&self) -> u32 {
5562        unsafe { ffi::rocksdb_options_get_bottommost_file_compaction_delay(self.inner) }
5563    }
5564
5565    /// If either DBOptions::allow_ingest_behind or this option is set to true, this column
5566    /// family will prepare for ingesting files to the last level (IngestExternalFiles() with
5567    /// ingest_behind=true). Users should set only this option since
5568    /// DBOptions::allow_ingest_behind is deprecated.
5569    ///
5570    /// Specifically, preparing a column family for ingesting files to the last level has the
5571    /// following effects:
5572    /// - Disables some internal optimizations around SST file compression.
5573    /// - Reserves the last level for ingested files only.
5574    /// - Compaction will not include any file from the last level.
5575    /// - Compaction will preserve necessary tombstones that can apply on top of ingested
5576    ///   files.
5577    ///
5578    /// Note that only Universal Compaction supports cf_allow_ingest_behind. `num_levels`
5579    /// should be >= 3 if this option is turned on.
5580    ///
5581    /// Note that this option needs to be set to true before any write to the CF. It's
5582    /// recommended to set the option to true since CF creation. Otherwise, ingestion with
5583    /// ingest_behind = true might fail. Once file ingestions are done, the option should be
5584    /// flipped to false. Flipping this option to false allows the CF to disable the behavior
5585    /// changes detailed above and resume more efficient operation.
5586    ///
5587    /// Default: false Immutable.
5588    pub fn set_cf_allow_ingest_behind(&mut self, val: bool) {
5589        unsafe {
5590            ffi::rocksdb_options_set_cf_allow_ingest_behind(self.inner, c_uchar::from(val));
5591        }
5592    }
5593
5594    /// Returns the value of the `cf_allow_ingest_behind` option.
5595    pub fn get_cf_allow_ingest_behind(&self) -> bool {
5596        unsafe { ffi::rocksdb_options_get_cf_allow_ingest_behind(self.inner) != 0 }
5597    }
5598
5599    /// Turns on checksum handoff for `file_type`, so RocksDB passes the crc32c it already
5600    /// computed down to the `FileSystem` instead of relying on the storage layer to protect
5601    /// the write on its own.
5602    ///
5603    /// Only enable this for a `FileSystem` that verifies crc32c. RocksDB generates nothing
5604    /// else, so a filesystem expecting a different checksum will reject the writes.
5605    ///
5606    /// RocksDB honours the set for [`FileType::WalFile`], [`FileType::TableFile`], and
5607    /// [`FileType::DescriptorFile`]. Other types can be added but are never consulted.
5608    /// [`FileType::CompactionProgressFile`] and [`FileType::Unknown`] fall outside the range
5609    /// RocksDB's file type set can hold and are ignored.
5610    ///
5611    /// Default: empty.
5612    pub fn add_checksum_handoff_file_type(&mut self, file_type: FileType) {
5613        let Some(raw) = checksum_handoff_file_type_raw(file_type) else {
5614            return;
5615        };
5616        unsafe {
5617            ffi::rocksdb_options_checksum_handoff_file_types_add(self.inner, raw);
5618        }
5619    }
5620
5621    /// Turns checksum handoff back off for `file_type`.
5622    ///
5623    /// Removing a type that is not in the set does nothing. See
5624    /// [`Self::add_checksum_handoff_file_type`].
5625    pub fn remove_checksum_handoff_file_type(&mut self, file_type: FileType) {
5626        let Some(raw) = checksum_handoff_file_type_raw(file_type) else {
5627            return;
5628        };
5629        unsafe {
5630            ffi::rocksdb_options_checksum_handoff_file_types_remove(self.inner, raw);
5631        }
5632    }
5633
5634    /// Turns checksum handoff off for every file type.
5635    ///
5636    /// See [`Self::add_checksum_handoff_file_type`].
5637    pub fn clear_checksum_handoff_file_types(&mut self) {
5638        unsafe {
5639            ffi::rocksdb_options_checksum_handoff_file_types_clear(self.inner);
5640        }
5641    }
5642
5643    /// Whether checksum handoff is on for `file_type`.
5644    ///
5645    /// Always false for the two types the set cannot hold, see
5646    /// [`Self::add_checksum_handoff_file_type`].
5647    pub fn contains_checksum_handoff_file_type(&self, file_type: FileType) -> bool {
5648        let Some(raw) = checksum_handoff_file_type_raw(file_type) else {
5649            return false;
5650        };
5651        unsafe { ffi::rocksdb_options_checksum_handoff_file_types_contains(self.inner, raw) != 0 }
5652    }
5653
5654    /// How many file types have checksum handoff turned on.
5655    ///
5656    /// See [`Self::add_checksum_handoff_file_type`].
5657    pub fn checksum_handoff_file_type_count(&self) -> usize {
5658        unsafe { ffi::rocksdb_options_checksum_handoff_file_types_count(self.inner) }
5659    }
5660
5661    /// DEPRECATED: This option might be removed in a future release.
5662    ///
5663    /// If true, during compaction, RocksDB will count the number of entries read and compare
5664    /// it against the number of entries in the compaction input files. This is intended to
5665    /// add protection against corruption during compaction. Note that
5666    /// - this verification is not done for compactions during which a compaction filter
5667    ///   returns kRemoveAndSkipUntil, and
5668    /// - the number of range deletions is not verified.
5669    ///
5670    /// The option is here to turn the feature off in case this new validation feature has a
5671    /// bug. The option may be removed in the future once the feature is stable.
5672    ///
5673    /// Default: true
5674    pub fn set_compaction_verify_record_count(&mut self, val: bool) {
5675        unsafe {
5676            ffi::rocksdb_options_set_compaction_verify_record_count(self.inner, c_uchar::from(val));
5677        }
5678    }
5679
5680    /// Returns the value of the `compaction_verify_record_count` option.
5681    pub fn get_compaction_verify_record_count(&self) -> bool {
5682        unsafe { ffi::rocksdb_options_get_compaction_verify_record_count(self.inner) != 0 }
5683    }
5684
5685    /// Declares a daily window of low read and write activity, in UTC, so RocksDB can pull
5686    /// low priority work such as TTL compaction into it instead of letting it land in the
5687    /// middle of a busy period.
5688    ///
5689    /// The format is `HH:mm-HH:mm`, inclusive on both ends, with hours in `00` to `23` and
5690    /// minutes in `00` to `59`. A start later than the end wraps past midnight, so
5691    /// `23:30-04:00` is a valid overnight window. `0:00-23:59` marks the whole day off-peak,
5692    /// and an empty string, the default, means there is no off-peak period.
5693    ///
5694    /// A string that does not parse is not reported here. RocksDB rejects it when the DB is
5695    /// opened, and `SetDBOptions` rejects it at runtime.
5696    ///
5697    /// # Errors
5698    ///
5699    /// Returns an error if `v` contains an interior NUL byte.
5700    pub fn set_daily_offpeak_time_utc(&mut self, v: impl CStrLike) -> Result<(), Error> {
5701        let v = v
5702            .bake()
5703            .map_err(|e| Error::new(format!("daily offpeak time must not contain NUL: {e}")))?;
5704        unsafe {
5705            ffi::rocksdb_options_set_daily_offpeak_time_utc(self.inner, v.as_ptr());
5706        }
5707        Ok(())
5708    }
5709
5710    /// The off-peak window set by [`Self::set_daily_offpeak_time_utc`], empty when there is
5711    /// none.
5712    pub fn get_daily_offpeak_time_utc(&self) -> String {
5713        let mut len: size_t = 0;
5714        let window =
5715            unsafe { ffi::rocksdb_options_get_daily_offpeak_time_utc(self.inner, &raw mut len) };
5716        unsafe { borrowed_string(window, len) }
5717    }
5718
5719    /// Names the machine hosting the DB. RocksDB writes it as a property into every SST file
5720    /// it produces, including files from `SstFileWriter` and `RepairDB`.
5721    ///
5722    /// It exists to trace memory corruption back to the host that wrote the file. Corruption
5723    /// that happens before RocksDB checksums the data is invisible to the checksum, so the
5724    /// host id is the only thing left pointing at the culprit.
5725    ///
5726    /// RocksDB substitutes the real hostname when this is left at its default. Setting it to
5727    /// an empty string leaves the property out of the SST file entirely.
5728    ///
5729    /// # Errors
5730    ///
5731    /// Returns an error if `v` contains an interior NUL byte.
5732    pub fn set_db_host_id(&mut self, v: impl CStrLike) -> Result<(), Error> {
5733        let v = v
5734            .bake()
5735            .map_err(|e| Error::new(format!("db host id must not contain NUL: {e}")))?;
5736        unsafe {
5737            ffi::rocksdb_options_set_db_host_id(self.inner, v.as_ptr());
5738        }
5739        Ok(())
5740    }
5741
5742    /// The host id set by [`Self::set_db_host_id`].
5743    ///
5744    /// An untouched `Options` returns the `__hostname__` placeholder rather than the real
5745    /// hostname, because RocksDB only resolves it while writing a file.
5746    pub fn get_db_host_id(&self) -> String {
5747        let mut len: size_t = 0;
5748        let host_id = unsafe { ffi::rocksdb_options_get_db_host_id(self.inner, &raw mut len) };
5749        unsafe { borrowed_string(host_id, len) }
5750    }
5751
5752    /// EXPERIMENTAL When this field is set, all SST files without an explicitly set
5753    /// temperature will be treated as if they have this temperature for file reading
5754    /// accounting purpose, such as io statistics, io perf context.
5755    ///
5756    /// Not dynamically changeable; change requires DB restart.
5757    pub fn set_default_temperature(&mut self, val: c_int) {
5758        unsafe {
5759            ffi::rocksdb_options_set_default_temperature(self.inner, val);
5760        }
5761    }
5762
5763    /// Returns the value of the `default_temperature` option.
5764    pub fn get_default_temperature(&self) -> c_int {
5765        unsafe { ffi::rocksdb_options_get_default_temperature(self.inner) }
5766    }
5767
5768    /// EXPERIMENTAL When no other option such as last_level_temperature determines the
5769    /// temperature of a new SST file, it will be written with this temperature, which can be
5770    /// set differently for each column family.
5771    ///
5772    /// Dynamically changeable through the SetOptions() API
5773    pub fn set_default_write_temperature(&mut self, val: c_int) {
5774        unsafe {
5775            ffi::rocksdb_options_set_default_write_temperature(self.inner, val);
5776        }
5777    }
5778
5779    /// Returns the value of the `default_write_temperature` option.
5780    pub fn get_default_write_temperature(&self) -> c_int {
5781        unsafe { ffi::rocksdb_options_get_default_write_temperature(self.inner) }
5782    }
5783
5784    /// The limited write rate to DB if soft_pending_compaction_bytes_limit or
5785    /// level0_slowdown_writes_trigger is triggered, or we are writing to the last mem table
5786    /// allowed and we allow more than 3 mem tables. It is calculated using size of user write
5787    /// requests before compression. RocksDB may decide to slow down more if the compaction
5788    /// still gets behind further. If the value is 0, we will infer a value from
5789    /// `rater_limiter` value if it is not empty, or 16MB if `rater_limiter` is empty. Note
5790    /// that if users change the rate in `rate_limiter` after DB is opened,
5791    /// `delayed_write_rate` won't be adjusted.
5792    ///
5793    /// Unit: byte per second.
5794    ///
5795    /// Default: 0
5796    ///
5797    /// Dynamically changeable through SetDBOptions() API.
5798    pub fn set_delayed_write_rate(&mut self, val: u64) {
5799        unsafe {
5800            ffi::rocksdb_options_set_delayed_write_rate(self.inner, val);
5801        }
5802    }
5803
5804    /// Returns the value of the `delayed_write_rate` option.
5805    pub fn get_delayed_write_rate(&self) -> u64 {
5806        unsafe { ffi::rocksdb_options_get_delayed_write_rate(self.inner) }
5807    }
5808
5809    /// Setting this option to true disallows ordinary writes to the column family and it can
5810    /// only be populated through import and ingestion. It is intended to protect "ingestion
5811    /// only" column families. This option is not currently supported on the default column
5812    /// family because of error handling challenges analogous to
5813    /// <https://github.com/facebook/rocksdb/issues/13429>
5814    ///
5815    /// This option is not mutable with SetOptions(). It can be changed between DB::Open()
5816    /// calls, but open will fail if recovering WAL writes to a CF with this option set.
5817    pub fn set_disallow_memtable_writes(&mut self, val: bool) {
5818        unsafe {
5819            ffi::rocksdb_options_set_disallow_memtable_writes(self.inner, c_uchar::from(val));
5820        }
5821    }
5822
5823    /// Returns the value of the `disallow_memtable_writes` option.
5824    pub fn get_disallow_memtable_writes(&self) -> bool {
5825        unsafe { ffi::rocksdb_options_get_disallow_memtable_writes(self.inner) != 0 }
5826    }
5827
5828    /// If true, then print malloc stats together with rocksdb.stats when printing to LOG.
5829    /// DEFAULT: false
5830    pub fn get_dump_malloc_stats(&self) -> bool {
5831        unsafe { ffi::rocksdb_options_get_dump_malloc_stats(self.inner) != 0 }
5832    }
5833
5834    /// When enabled, values >= min_blob_size are written directly to blob files during the
5835    /// write path and replaced in WAL and memtable with BlobIndex references.
5836    ///
5837    /// Requires enable_blob_files = true. Experimental reduced-scope v1 restrictions. These
5838    /// limitations keep the v1 implementation intentionally small; follow-up PRs are expected
5839    /// to improve feature compatibility over time:
5840    /// - only supports the ordered single-memtable-writer path; unordered, pipelined,
5841    ///   two_write_queues, and allow_concurrent_memtable_write are not supported.
5842    /// - crash recovery only supports blob files that were already made manifest-visible by
5843    ///   flush/SST creation; WAL replay of active direct-write blob files is not currently
5844    ///   supported.
5845    /// - checkpoint/backup/live-files enumeration must flush pending direct-write state
5846    ///   first; APIs that intentionally skip the flush, or run while WAL is locked, can
5847    ///   return NotSupported.
5848    /// - not compatible with MemPurge or user-defined timestamps.
5849    /// - DB::IngestWriteBatchWithIndex() is not supported while any live column family
5850    ///   enables this option.
5851    /// - read-only and secondary opens can read flushed/manifest-visible blob files, but do
5852    ///   not resolve still-active direct-write blob files.
5853    ///
5854    /// Default: false
5855    ///
5856    /// Not dynamically changeable through the SetOptions() API.
5857    pub fn set_enable_blob_direct_write(&mut self, val: bool) {
5858        unsafe {
5859            ffi::rocksdb_options_set_enable_blob_direct_write(self.inner, c_uchar::from(val));
5860        }
5861    }
5862
5863    /// Returns the value of the `enable_blob_direct_write` option.
5864    pub fn get_enable_blob_direct_write(&self) -> bool {
5865        unsafe { ffi::rocksdb_options_get_enable_blob_direct_write(self.inner) != 0 }
5866    }
5867
5868    /// If true, then the status of the threads involved in this DB will be tracked and
5869    /// available via GetThreadList() API.
5870    ///
5871    /// Default: false
5872    pub fn set_enable_thread_tracking(&mut self, val: bool) {
5873        unsafe {
5874            ffi::rocksdb_options_set_enable_thread_tracking(self.inner, c_uchar::from(val));
5875        }
5876    }
5877
5878    /// Returns the value of the `enable_thread_tracking` option.
5879    pub fn get_enable_thread_tracking(&self) -> bool {
5880        unsafe { ffi::rocksdb_options_get_enable_thread_tracking(self.inner) != 0 }
5881    }
5882
5883    /// DEPRECATED: This option might be removed in a future release.
5884    ///
5885    /// If set to false, when compaction or flush sees a SingleDelete followed by a Delete for
5886    /// the same user key, compaction job will not fail. Otherwise, compaction job will fail.
5887    /// This is a temporary option to help existing use cases migrate, and will be removed in
5888    /// a future release. Warning: do not set to false unless you are trying to migrate
5889    /// existing data in which the contract of single delete
5890    /// (<https://github.com/facebook/rocksdb/wiki/Single-Delete>) is not enforced, thus has
5891    /// Delete mixed with SingleDelete for the same user key. Violation of the contract leads
5892    /// to undefined behaviors with high possibility of data inconsistency, e.g. deleted old
5893    /// data become visible again, etc.
5894    pub fn set_enforce_single_del_contracts(&mut self, val: bool) {
5895        unsafe {
5896            ffi::rocksdb_options_set_enforce_single_del_contracts(self.inner, c_uchar::from(val));
5897        }
5898    }
5899
5900    /// Returns the value of the `enforce_single_del_contracts` option.
5901    pub fn get_enforce_single_del_contracts(&self) -> bool {
5902        unsafe { ffi::rocksdb_options_get_enforce_single_del_contracts(self.inner) != 0 }
5903    }
5904
5905    /// If true and a WriteBufferManager is configured, RocksDB will check
5906    /// WriteBufferManager::ShouldFlush() during WAL recovery and schedule flushes when
5907    /// needed. This prevents OOM when multiple RocksDB instances share a WriteBufferManager
5908    /// and one instance is recovering from WAL.
5909    ///
5910    /// When triggered, all column families with non-empty memtables are scheduled for flush,
5911    /// which may produce smaller L0 files in some column families. This also overrides
5912    /// `avoid_flush_during_recovery`: once a WBM-triggered flush occurs mid-recovery, all
5913    /// remaining non-empty memtables will be flushed at the end of recovery as well.
5914    ///
5915    /// DEFAULT: true
5916    pub fn set_enforce_write_buffer_manager_during_recovery(&mut self, val: bool) {
5917        unsafe {
5918            ffi::rocksdb_options_set_enforce_write_buffer_manager_during_recovery(
5919                self.inner,
5920                c_uchar::from(val),
5921            );
5922        }
5923    }
5924
5925    /// Returns the value of the `enforce_write_buffer_manager_during_recovery` option.
5926    pub fn get_enforce_write_buffer_manager_during_recovery(&self) -> bool {
5927        unsafe {
5928            ffi::rocksdb_options_get_enforce_write_buffer_manager_during_recovery(self.inner) != 0
5929        }
5930    }
5931
5932    /// EXPERIMENTAL When this is true, save file system metadata (if supported by the FS) for
5933    /// SST files added to the DB in the MANIFEST, and use it to accelerate re-opening of
5934    /// those files on DB open. This will help cut down DB open latency on remote storage
5935    /// systems.
5936    pub fn set_fast_sst_open(&mut self, val: bool) {
5937        unsafe {
5938            ffi::rocksdb_options_set_fast_sst_open(self.inner, c_uchar::from(val));
5939        }
5940    }
5941
5942    /// Returns the value of the `fast_sst_open` option.
5943    pub fn get_fast_sst_open(&self) -> bool {
5944        unsafe { ffi::rocksdb_options_get_fast_sst_open(self.inner) != 0 }
5945    }
5946
5947    /// DEPRECATED: This option might be removed in a future release.
5948    ///
5949    /// If true, during memtable flush, RocksDB will validate total entries read in flush,
5950    /// total entries written in the SST and compare them with counter of keys added.
5951    ///
5952    /// The option is here to turn the feature off in case this new validation feature has a
5953    /// bug. The option may be removed in the future once the feature is stable.
5954    ///
5955    /// Default: true
5956    pub fn set_flush_verify_memtable_count(&mut self, val: bool) {
5957        unsafe {
5958            ffi::rocksdb_options_set_flush_verify_memtable_count(self.inner, c_uchar::from(val));
5959        }
5960    }
5961
5962    /// Returns the value of the `flush_verify_memtable_count` option.
5963    pub fn get_flush_verify_memtable_count(&self) -> bool {
5964        unsafe { ffi::rocksdb_options_get_flush_verify_memtable_count(self.inner) != 0 }
5965    }
5966
5967    /// For a given catch up attempt, this option specifies the number of times to tail the
5968    /// MANIFEST and try to install a new, consistent  version before giving up. Though it
5969    /// should be extremely rare, the catch up may fail if the leader is mutating the LSM at a
5970    /// very high rate and the follower is unable to get a consistent view. Default to 10
5971    /// attempts
5972    pub fn set_follower_catchup_retry_count(&mut self, val: u64) {
5973        unsafe {
5974            ffi::rocksdb_options_set_follower_catchup_retry_count(self.inner, val);
5975        }
5976    }
5977
5978    /// Returns the value of the `follower_catchup_retry_count` option.
5979    pub fn get_follower_catchup_retry_count(&self) -> u64 {
5980        unsafe { ffi::rocksdb_options_get_follower_catchup_retry_count(self.inner) }
5981    }
5982
5983    /// Time to wait between consecutive catch up attempts Default 100ms
5984    pub fn set_follower_catchup_retry_wait_ms(&mut self, val: u64) {
5985        unsafe {
5986            ffi::rocksdb_options_set_follower_catchup_retry_wait_ms(self.inner, val);
5987        }
5988    }
5989
5990    /// Returns the value of the `follower_catchup_retry_wait_ms` option.
5991    pub fn get_follower_catchup_retry_wait_ms(&self) -> u64 {
5992        unsafe { ffi::rocksdb_options_get_follower_catchup_retry_wait_ms(self.inner) }
5993    }
5994
5995    /// When a RocksDB database is opened in follower mode, this option is set by the user to
5996    /// request the frequency of the follower attempting to refresh its view of the leader.
5997    /// RocksDB may choose to trigger catch ups more frequently if it detects any changes in
5998    /// the database state. Default every 10s.
5999    pub fn set_follower_refresh_catchup_period_ms(&mut self, val: u64) {
6000        unsafe {
6001            ffi::rocksdb_options_set_follower_refresh_catchup_period_ms(self.inner, val);
6002        }
6003    }
6004
6005    /// Returns the value of the `follower_refresh_catchup_period_ms` option.
6006    pub fn get_follower_refresh_catchup_period_ms(&self) -> u64 {
6007        unsafe { ffi::rocksdb_options_get_follower_refresh_catchup_period_ms(self.inner) }
6008    }
6009
6010    /// In debug mode, RocksDB runs consistency checks on the LSM every time the LSM changes
6011    /// (Flush, Compaction, AddFile). When this option is true, these checks are also enabled
6012    /// in release mode. These checks were historically disabled in release mode, but are now
6013    /// enabled by default for proactive corruption detection. The CPU overhead is negligible
6014    /// for normal mixed operations but can slow down saturated writing. See
6015    /// Options::DisableExtraChecks(). Default: true
6016    pub fn set_force_consistency_checks(&mut self, val: bool) {
6017        unsafe {
6018            ffi::rocksdb_options_set_force_consistency_checks(self.inner, c_uchar::from(val));
6019        }
6020    }
6021
6022    /// Returns the value of the `force_consistency_checks` option.
6023    pub fn get_force_consistency_checks(&self) -> bool {
6024        unsafe { ffi::rocksdb_options_get_force_consistency_checks(self.inner) != 0 }
6025    }
6026
6027    /// EXPERIMENTAL If this option is set, when creating the last level files, pass this
6028    /// temperature to FileSystem used. Should be no-op for default FileSystem and users need
6029    /// to plug in their own FileSystem to take advantage of it. Currently only compatible
6030    /// with universal compaction.
6031    ///
6032    /// Dynamically changeable through the SetOptions() API
6033    pub fn set_last_level_temperature(&mut self, val: c_int) {
6034        unsafe {
6035            ffi::rocksdb_options_set_last_level_temperature(self.inner, val);
6036        }
6037    }
6038
6039    /// Returns the value of the `last_level_temperature` option.
6040    pub fn get_last_level_temperature(&self) -> c_int {
6041        unsafe { ffi::rocksdb_options_get_last_level_temperature(self.inner) }
6042    }
6043
6044    /// The number of bytes to prefetch when reading the DB manifest and WAL files during
6045    /// DB::Open (and variants). This is mostly useful for reading a remotely located log, as
6046    /// it can save the number of round-trips. If 0, then the prefetching is disabled.
6047    ///
6048    /// Default: 0
6049    pub fn set_log_readahead_size(&mut self, val: usize) {
6050        unsafe {
6051            ffi::rocksdb_options_set_log_readahead_size(self.inner, val);
6052        }
6053    }
6054
6055    /// Returns the value of the `log_readahead_size` option.
6056    pub fn get_log_readahead_size(&self) -> usize {
6057        unsafe { ffi::rocksdb_options_get_log_readahead_size(self.inner) }
6058    }
6059
6060    /// It indicates, which lowest cache tier we want to use for a certain DB. Currently we
6061    /// support volatile_tier and non_volatile_tier. They are layered. By setting it to
6062    /// kVolatileTier, only the block cache (current implemented volatile_tier) is used. So
6063    /// cache entries will not spill to secondary cache (current implemented
6064    /// non_volatile_tier), and block cache lookup misses will not lookup in the secondary
6065    /// cache. When kNonVolatileBlockTier is used, we use both block cache and secondary
6066    /// cache.
6067    ///
6068    /// Default: kNonVolatileBlockTier
6069    pub fn set_lowest_used_cache_tier(&mut self, val: c_int) {
6070        unsafe {
6071            ffi::rocksdb_options_set_lowest_used_cache_tier(self.inner, val);
6072        }
6073    }
6074
6075    /// Returns the value of the `lowest_used_cache_tier` option.
6076    pub fn get_lowest_used_cache_tier(&self) -> c_int {
6077        unsafe { ffi::rocksdb_options_get_lowest_used_cache_tier(self.inner) }
6078    }
6079
6080    /// It defines how many times DB::Resume() is called by a separate thread when background
6081    /// retryable IO Error happens. When background retryable IO Error happens, SetBGError is
6082    /// called to deal with the error. If the error can be auto-recovered (e.g., retryable IO
6083    /// Error during Flush or WAL write), then db resume is called in background to recover
6084    /// from the error. If this value is 0 or negative, DB::Resume() will not be called
6085    /// automatically.
6086    ///
6087    /// Default: INT_MAX
6088    pub fn set_max_bgerror_resume_count(&mut self, val: c_int) {
6089        unsafe {
6090            ffi::rocksdb_options_set_max_bgerror_resume_count(self.inner, val);
6091        }
6092    }
6093
6094    /// Returns the value of the `max_bgerror_resume_count` option.
6095    pub fn get_max_bgerror_resume_count(&self) -> c_int {
6096        unsafe { ffi::rocksdb_options_get_max_bgerror_resume_count(self.inner) }
6097    }
6098
6099    /// Maximum interval in seconds between periodic compaction trigger checks. The periodic
6100    /// trigger re-evaluates compaction scores for all column families, which is necessary for
6101    /// features like read-triggered compaction and time-based compaction to work on a "quiet"
6102    /// DB with no writes.
6103    ///
6104    /// This is an upper bound: the actual check interval may be reduced to align with
6105    /// stats_dump_period_sec, stats_persist_period_sec, or per-CF time-based compaction
6106    /// intervals (periodic_compaction_seconds, ttl, etc.).
6107    ///
6108    /// Note: this option controls how often RocksDB *checks* whether compaction is needed. It
6109    /// is different from the CF option `periodic_compaction_seconds` which controls the *age
6110    /// threshold* at which SST files become eligible for periodic compaction.
6111    ///
6112    /// The minimum effective period is 1 second (values below 1 are clamped to 1). Setting
6113    /// this to 0 results in the most aggressive 1-second polling.
6114    ///
6115    /// Default: 43200 (12 hours)
6116    ///
6117    /// Dynamically changeable through SetDBOptions() API.
6118    pub fn set_max_compaction_trigger_wakeup_seconds(&mut self, val: u64) {
6119        unsafe {
6120            ffi::rocksdb_options_set_max_compaction_trigger_wakeup_seconds(self.inner, val);
6121        }
6122    }
6123
6124    /// Returns the value of the `max_compaction_trigger_wakeup_seconds` option.
6125    pub fn get_max_compaction_trigger_wakeup_seconds(&self) -> u64 {
6126        unsafe { ffi::rocksdb_options_get_max_compaction_trigger_wakeup_seconds(self.inner) }
6127    }
6128
6129    /// This option mostly replaces max_manifest_file_size to control an auto-tuned balance of
6130    /// manifest write amplification and space amplification. A new manifest file is created
6131    /// with the "compacted" contents of the old one when current_manifest_size >
6132    /// max(max_manifest_file_size, est_compacted_manifest_size * (1 +
6133    /// max_manifest_space_amp_pct/100))
6134    ///
6135    /// where est_compacted_manifest_size is an estimate of how big a new compacted version of
6136    /// the current manifest would be. Currently, the estimate used is the last newly-written
6137    /// manifest, in its "compacted" form.
6138    ///
6139    /// Space amplification in the manifest file might be less of a concern for primary
6140    /// storage space and more of a concern for DB recover time and size of backup files that
6141    /// aren't incremental between backups. To minimize manifest churn on initial DB
6142    /// population, setting max_manifest_file_size to something not too small, like 1MB,
6143    /// should suffice. Similarly, write amp on the manifest file is likely not a direct
6144    /// concern but completed compactions and flushes cannot (currently) be committed while
6145    /// the (relatively small) manifest file is being compacted. Manifest compactions should
6146    /// not interfere with user write latency or throughput unless the DB is chronically
6147    /// stalling or close to stalling writes already.
6148    ///
6149    /// For this option to have a meaningful effect, it is recommended to set
6150    /// max_manifest_file_size to something modest like 1MB. Then we can interpret values for
6151    /// this option as follows, starting with minimum space amp and maximum write amp:
6152    /// - 0 - Every manifest write (flush, compaction, etc.) generates a whole new manifest.
6153    ///   Only useful for testing.
6154    /// - very small - Doesn't take many manifest writes to generate a whole new manifest.
6155    /// - 100 - In a DB with pretty consistent number of SST files, etc., achieves about 1.0
6156    ///   write amp (writing about 2x the theoretical minimum) and a max of about 1.0 space
6157    ///   amp (manifest up to 2x the compacted size).
6158    /// - 500 - Recommended and default: 0.2 write amp and up to roughly 5.0 space amp.
6159    /// - 10000 - 0.01 write amp and up to 100 space amp on the manifest.
6160    ///
6161    /// This option is mutable with SetDBOptions(), taking effect on the next manifest write
6162    /// (e.g. completed DB compaction or flush).
6163    pub fn set_max_manifest_space_amp_pct(&mut self, val: c_int) {
6164        unsafe {
6165            ffi::rocksdb_options_set_max_manifest_space_amp_pct(self.inner, val);
6166        }
6167    }
6168
6169    /// Returns the value of the `max_manifest_space_amp_pct` option.
6170    pub fn get_max_manifest_space_amp_pct(&self) -> c_int {
6171        unsafe { ffi::rocksdb_options_get_max_manifest_space_amp_pct(self.inner) }
6172    }
6173
6174    /// The maximum limit of number of bytes that are written in a single batch of WAL or
6175    /// memtable write. It is followed when the leader write size is larger than 1/8 of this
6176    /// limit.
6177    ///
6178    /// Default: 1 MB
6179    pub fn set_max_write_batch_group_size_bytes(&mut self, val: u64) {
6180        unsafe {
6181            ffi::rocksdb_options_set_max_write_batch_group_size_bytes(self.inner, val);
6182        }
6183    }
6184
6185    /// Returns the value of the `max_write_batch_group_size_bytes` option.
6186    pub fn get_max_write_batch_group_size_bytes(&self) -> u64 {
6187        unsafe { ffi::rocksdb_options_get_max_write_batch_group_size_bytes(self.inner) }
6188    }
6189
6190    /// RocksDB will try to flush the current memtable after the number of range deletions is
6191    /// \>= this limit. For workloads with many range deletions, limiting the number of range
6192    /// deletions in memtable can help prevent performance degradation and/or OOM caused by
6193    /// too many range tombstones in a single memtable.
6194    ///
6195    /// Default: 0 (disabled)
6196    ///
6197    /// Dynamically changeable through SetOptions() API
6198    pub fn set_memtable_max_range_deletions(&mut self, val: u32) {
6199        unsafe {
6200            ffi::rocksdb_options_set_memtable_max_range_deletions(self.inner, val);
6201        }
6202    }
6203
6204    /// Returns the value of the `memtable_max_range_deletions` option.
6205    pub fn get_memtable_max_range_deletions(&self) -> u32 {
6206        unsafe { ffi::rocksdb_options_get_memtable_max_range_deletions(self.inner) }
6207    }
6208
6209    /// Enable memtable per key-value checksum protection.
6210    ///
6211    /// Each entry in memtable will be suffixed by a per key-value checksum. This options
6212    /// determines the size of such checksums.
6213    ///
6214    /// It is suggested to turn on write batch per key-value checksum protection together with
6215    /// this option, so that the checksum computation is done outside of writer threads
6216    /// (memtable kv checksum can be computed from write batch checksum) See
6217    /// WriteOptions::protection_bytes_per_key for more detail.
6218    ///
6219    /// Default: 0 (no protection) Supported values: 0, 1, 2, 4, 8. Dynamically changeable
6220    /// through the SetOptions() API.
6221    pub fn set_memtable_protection_bytes_per_key(&mut self, val: u32) {
6222        unsafe {
6223            ffi::rocksdb_options_set_memtable_protection_bytes_per_key(self.inner, val);
6224        }
6225    }
6226
6227    /// Returns the value of the `memtable_protection_bytes_per_key` option.
6228    pub fn get_memtable_protection_bytes_per_key(&self) -> u32 {
6229        unsafe { ffi::rocksdb_options_get_memtable_protection_bytes_per_key(self.inner) }
6230    }
6231
6232    /// Enables additional integrity checks during seek. Specifically, for skiplist-based
6233    /// memtables, key checksum validation could be enabled during seek optionally. This is
6234    /// helpful to detect corrupted memtable keys during reads. Enabling this feature incurs a
6235    /// performance overhead due to additional key checksum validation during memtable seek
6236    /// operation. This option depends on memtable_protection_bytes_per_key to be non zero. If
6237    /// memtable_protection_bytes_per_key is zero, no validation is performed.
6238    pub fn set_memtable_verify_per_key_checksum_on_seek(&mut self, val: bool) {
6239        unsafe {
6240            ffi::rocksdb_options_set_memtable_verify_per_key_checksum_on_seek(
6241                self.inner,
6242                c_uchar::from(val),
6243            );
6244        }
6245    }
6246
6247    /// Returns the value of the `memtable_verify_per_key_checksum_on_seek` option.
6248    pub fn get_memtable_verify_per_key_checksum_on_seek(&self) -> bool {
6249        unsafe {
6250            ffi::rocksdb_options_get_memtable_verify_per_key_checksum_on_seek(self.inner) != 0
6251        }
6252    }
6253
6254    /// Enable whole key bloom filter in memtable. Note this will only take effect if
6255    /// memtable_prefix_bloom_size_ratio is not 0. Enabling whole key filtering can
6256    /// potentially reduce CPU usage for point-look-ups.
6257    ///
6258    /// Default: false (disabled)
6259    ///
6260    /// Dynamically changeable through SetOptions() API
6261    pub fn get_memtable_whole_key_filtering(&self) -> bool {
6262        unsafe { ffi::rocksdb_options_get_memtable_whole_key_filtering(self.inner) != 0 }
6263    }
6264
6265    /// When DB files other than SST, blob and WAL files are created, use this filesystem
6266    /// temperature. (See also `wal_write_temperature` and various `*_temperature` CF
6267    /// options.) When not `kUnknown`, this overrides any temperature set by
6268    /// OptimizeForManifestWrite functions.
6269    pub fn set_metadata_write_temperature(&mut self, val: c_int) {
6270        unsafe {
6271            ffi::rocksdb_options_set_metadata_write_temperature(self.inner, val);
6272        }
6273    }
6274
6275    /// Returns the value of the `metadata_write_temperature` option.
6276    pub fn get_metadata_write_temperature(&self) -> c_int {
6277        unsafe { ffi::rocksdb_options_get_metadata_write_temperature(self.inner) }
6278    }
6279
6280    /// EXPERIMENTAL
6281    ///
6282    /// During forward or reverse iteration, when this many or more strictly contiguous point
6283    /// tombstones (kTypeDeletion, kTypeDeletionWithTimestamp, kTypeSingleDeletion) are
6284    /// encountered with no live keys between them, a range tombstone [first_tombstone_key,
6285    /// next_live_key) is inserted into the current mutable memtable (only if memtable is not
6286    /// empty). This is a logically redundant entry that does not change any data, but
6287    /// optimizes future iterators by potentially skipping a large number of tombstone scans.
6288    ///
6289    /// This optimization is best-effort and is currently disabled for iterator configurations
6290    /// that may not expose all interior live keys, including:
6291    /// - user-defined timestamp reads without full visibility (for example,
6292    ///   ReadOptions::iter_start_ts or a non-max ReadOptions::timestamp)
6293    /// - prefix extractor reads that are neither total-order (ReadOptions::total_order_seek
6294    ///   / ReadOptions::auto_prefix_mode) nor bounded by ReadOptions::prefix_same_as_start
6295    ///
6296    /// Even if the above restrictions are met, there are still scenarios where a converted
6297    /// range tombstone may be discarded:
6298    /// - The snapshot's active mutable memtable has already become immutable.
6299    /// - The iterator's snapshot seq is below the active memtable's earliest sequence
6300    ///   number.
6301    /// - A range tombstone covering [first_tombstone_key, next_live_key) is already present
6302    ///   in the memtable.
6303    /// - A WritePrepared/WriteUnprepared transaction read callback is in use and the
6304    ///   snapshot seq is at or above its min uncommitted seq.
6305    /// - An IngestExternalFile call is currently in flight on this column family OR the
6306    ///   inserted range tombstone seqno would be lower than the ingested file seqno.
6307    ///
6308    /// Read-write iterators using ReadOptions::table_filter are rejected while this option is
6309    /// enabled, see more details in ReadOptions::table_filter comments.
6310    ///
6311    /// Set to 0 to disable.
6312    ///
6313    /// Dynamically changeable through SetOptions() API
6314    pub fn set_min_tombstones_for_range_conversion(&mut self, val: u32) {
6315        unsafe {
6316            ffi::rocksdb_options_set_min_tombstones_for_range_conversion(self.inner, val);
6317        }
6318    }
6319
6320    /// Returns the value of the `min_tombstones_for_range_conversion` option.
6321    pub fn get_min_tombstones_for_range_conversion(&self) -> u32 {
6322        unsafe { ffi::rocksdb_options_get_min_tombstones_for_range_conversion(self.inner) }
6323    }
6324
6325    /// EXPERIMENTAL: If true, RocksDB can reduce recovery work after a clean shutdown, which
6326    /// may reduce DB::Open latency on warm reopens, especially on storage where metadata
6327    /// appends are expensive.
6328    ///
6329    /// Best-effort optimization: if it is disabled or unavailable, RocksDB falls back to the
6330    /// standard recovery path.
6331    ///
6332    /// Temporary rollout / kill switch for an optimization that is intended to be correct and
6333    /// eventually always enabled. Mutable via SetDBOptions().
6334    pub fn set_optimize_manifest_for_recovery(&mut self, val: bool) {
6335        unsafe {
6336            ffi::rocksdb_options_set_optimize_manifest_for_recovery(self.inner, c_uchar::from(val));
6337        }
6338    }
6339
6340    /// Returns the value of the `optimize_manifest_for_recovery` option.
6341    pub fn get_optimize_manifest_for_recovery(&self) -> bool {
6342        unsafe { ffi::rocksdb_options_get_optimize_manifest_for_recovery(self.inner) != 0 }
6343    }
6344
6345    /// After writing every SST file, reopen it and read all the keys. Checks the hash of all
6346    /// of the keys and values written versus the keys in the file and signals a corruption if
6347    /// they do not match
6348    ///
6349    /// Default: false
6350    ///
6351    /// Dynamically changeable through SetOptions() API
6352    pub fn set_paranoid_file_checks(&mut self, val: bool) {
6353        unsafe {
6354            ffi::rocksdb_options_set_paranoid_file_checks(self.inner, c_uchar::from(val));
6355        }
6356    }
6357
6358    /// Returns the value of the `paranoid_file_checks` option.
6359    pub fn get_paranoid_file_checks(&self) -> bool {
6360        unsafe { ffi::rocksdb_options_get_paranoid_file_checks(self.inner) != 0 }
6361    }
6362
6363    /// Enables additional integrity checks during reads/scans. Specifically, for
6364    /// skiplist-based memtables, key ordering validation could be enabled optionally. This is
6365    /// helpful to detect corrupted memtable keys during reads. Enabling this feature incurs a
6366    /// performance overhead due to additional comparison during memtable lookup.
6367    pub fn set_paranoid_memory_checks(&mut self, val: bool) {
6368        unsafe {
6369            ffi::rocksdb_options_set_paranoid_memory_checks(self.inner, c_uchar::from(val));
6370        }
6371    }
6372
6373    /// Returns the value of the `paranoid_memory_checks` option.
6374    pub fn get_paranoid_memory_checks(&self) -> bool {
6375        unsafe { ffi::rocksdb_options_get_paranoid_memory_checks(self.inner) != 0 }
6376    }
6377
6378    /// If true, automatically persist stats to a hidden column family (column family name:
6379    /// ___rocksdb_stats_history___) every stats_persist_period_sec seconds; otherwise, write
6380    /// to an in-memory struct. User can query through `GetStatsHistory` API. If user attempts
6381    /// to create a column family with the same name on a DB which have previously set
6382    /// persist_stats_to_disk to true, the column family creation will fail, but the hidden
6383    /// column family will survive, as well as the previously persisted statistics. When
6384    /// peristing stats to disk, the stat name will be limited at 100 bytes. Default: false
6385    pub fn set_persist_stats_to_disk(&mut self, val: bool) {
6386        unsafe {
6387            ffi::rocksdb_options_set_persist_stats_to_disk(self.inner, c_uchar::from(val));
6388        }
6389    }
6390
6391    /// Returns the value of the `persist_stats_to_disk` option.
6392    pub fn get_persist_stats_to_disk(&self) -> bool {
6393        unsafe { ffi::rocksdb_options_get_persist_stats_to_disk(self.inner) != 0 }
6394    }
6395
6396    /// UNDER CONSTRUCTION -- DO NOT USE When the user-defined timestamp feature is enabled,
6397    /// this flag controls whether the user-defined timestamps will be persisted.
6398    ///
6399    /// When it's false, the user-defined timestamps will be removed from the user keys when
6400    /// data is flushed from memtables to SST files. Other places that user keys can be
6401    /// persisted like file boundaries in file metadata and blob files go through a similar
6402    /// process. There are two major motivations for this flag:
6403    /// - backward compatibility: if the user later decides to disable the user-defined
6404    ///   timestamp feature for the column family, these SST files can be handled by a user
6405    ///   comparator that is not aware of user-defined timestamps.
6406    /// - enable user-defined timestamp feature for an existing column family while set this
6407    ///   flag to be `false`: user keys in the newly generated SST files are of the same
6408    ///   format as the existing SST files.
6409    ///
6410    /// Currently only user comparator that formats user-defined timesamps as uint64_t via
6411    /// using one of the RocksDB provided comparator `ComparatorWithU64TsImpl` are supported.
6412    ///
6413    /// When setting this flag to `false`, users should also call
6414    /// `DB::IncreaseFullHistoryTsLow` to set a cutoff timestamp for flush. RocksDB refrains
6415    /// from flushing a memtable with data still above the cutoff timestamp with best effort.
6416    /// One limitation of this best effort is that when `max_write_buffer_number` is equal to
6417    /// or smaller than 2, RocksDB will not attempt to retain user-defined timestamps, all
6418    /// flush jobs continue normally.
6419    ///
6420    /// Users can do user-defined multi-versioned read above the cutoff timestamp. When users
6421    /// try to read below the cutoff timestamp, an error will be returned.
6422    ///
6423    /// Note that if WAL is enabled, unlike SST files, user-defined timestamps are persisted
6424    /// to WAL even if this flag is set to `false`. The benefit of this is that user-defined
6425    /// timestamps can be recovered with the caveat that users should flush all memtables so
6426    /// there is no active WAL files before doing a downgrade. In order to use WAL to recover
6427    /// user-defined timestamps, users of this feature would want to set both
6428    /// `avoid_flush_during_shutdown` and `avoid_flush_during_recovery` to be true.
6429    ///
6430    /// Note that setting this flag to false is not supported in combination with atomic
6431    /// flush, or concurrent memtable write enabled by `allow_concurrent_memtable_write`.
6432    ///
6433    /// Default: true (user-defined timestamps are persisted) Not dynamically changeable,
6434    /// change it requires db restart and only compatible changes are allowed.
6435    pub fn set_persist_user_defined_timestamps(&mut self, val: bool) {
6436        unsafe {
6437            ffi::rocksdb_options_set_persist_user_defined_timestamps(
6438                self.inner,
6439                c_uchar::from(val),
6440            );
6441        }
6442    }
6443
6444    /// Returns the value of the `persist_user_defined_timestamps` option.
6445    pub fn get_persist_user_defined_timestamps(&self) -> bool {
6446        unsafe { ffi::rocksdb_options_get_persist_user_defined_timestamps(self.inner) != 0 }
6447    }
6448
6449    /// EXPERIMENTAL The feature is still in development and is incomplete. If this option is
6450    /// set, when data insert time is within this time range, it will be precluded from the
6451    /// last level. 0 means no key will be precluded from the last level.
6452    ///
6453    /// Note: when enabled, universal size amplification (controlled by option
6454    /// `compaction_options_universal.max_size_amplification_percent`) calculation will
6455    /// exclude the last level. As the feature is designed for tiered storage and a typical
6456    /// setting is the last level is cold tier which is likely not size constrained, the size
6457    /// amp is going to be only for non-last levels.
6458    ///
6459    /// Default: 0 (disable the feature)
6460    ///
6461    /// Dynamically changeable through the SetOptions() API
6462    pub fn set_preclude_last_level_data_seconds(&mut self, val: u64) {
6463        unsafe {
6464            ffi::rocksdb_options_set_preclude_last_level_data_seconds(self.inner, val);
6465        }
6466    }
6467
6468    /// Returns the value of the `preclude_last_level_data_seconds` option.
6469    pub fn get_preclude_last_level_data_seconds(&self) -> u64 {
6470        unsafe { ffi::rocksdb_options_get_preclude_last_level_data_seconds(self.inner) }
6471    }
6472
6473    /// Historically, when prefix_extractor != nullptr, iterators have an unfortunate default
6474    /// semantics of *possibly* only returning data within the same prefix. To avoid "spooky
6475    /// action at a distance," iterator bounds should come from the instantiation or seeking
6476    /// of the iterator, not from a mutable column family option.
6477    ///
6478    /// When set to true, it is as if every iterator is created with total_order_seek=true and
6479    /// only auto_prefix_mode=true and prefix_same_as_start=true can take advantage of prefix
6480    /// seek optimizations.
6481    pub fn set_prefix_seek_opt_in_only(&mut self, val: bool) {
6482        unsafe {
6483            ffi::rocksdb_options_set_prefix_seek_opt_in_only(self.inner, c_uchar::from(val));
6484        }
6485    }
6486
6487    /// Returns the value of the `prefix_seek_opt_in_only` option.
6488    pub fn get_prefix_seek_opt_in_only(&self) -> bool {
6489        unsafe { ffi::rocksdb_options_get_prefix_seek_opt_in_only(self.inner) != 0 }
6490    }
6491
6492    /// EXPERIMENTAL If this option is set, it will preserve the internal time information
6493    /// about the data until it's older than the specified time here. Internally the time
6494    /// information is a map between sequence number and time, which is the same as
6495    /// `preclude_last_level_data_seconds`. But it won't preclude the data from the last level
6496    /// and the data in the last level won't have the sequence number zeroed out. Internally,
6497    /// rocksdb would sample the sequence number to time pair and store that in SST property
6498    /// "rocksdb.seqno.time.map". The information is currently only used for tiered storage
6499    /// compaction (option `preclude_last_level_data_seconds`).
6500    ///
6501    /// Note: if both `preclude_last_level_data_seconds` and this option is set, it will
6502    /// preserve the max time of the 2 options and compaction still preclude the data based on
6503    /// `preclude_last_level_data_seconds`. The higher the preserve_time is, the less the
6504    /// sampling frequency will be ( which means less accuracy of the time estimation).
6505    ///
6506    /// Default: 0 (disable the feature)
6507    ///
6508    /// Dynamically changeable through the SetOptions() API
6509    pub fn set_preserve_internal_time_seconds(&mut self, val: u64) {
6510        unsafe {
6511            ffi::rocksdb_options_set_preserve_internal_time_seconds(self.inner, val);
6512        }
6513    }
6514
6515    /// Returns the value of the `preserve_internal_time_seconds` option.
6516    pub fn get_preserve_internal_time_seconds(&self) -> u64 {
6517        unsafe { ffi::rocksdb_options_get_preserve_internal_time_seconds(self.inner) }
6518    }
6519
6520    /// Requested maximum number of threads in the shared read I/O executor. A DB open can
6521    /// increase the executor to this size but cannot reduce it. Used exclusively for
6522    /// asynchronous read requests (e.g. GetAsync, MultiGetAsync).
6523    pub fn set_read_io_executor_threads(&mut self, val: c_int) {
6524        unsafe {
6525            ffi::rocksdb_options_set_read_io_executor_threads(self.inner, val);
6526        }
6527    }
6528
6529    /// Returns the value of the `read_io_executor_threads` option.
6530    pub fn get_read_io_executor_threads(&self) -> c_int {
6531        unsafe { ffi::rocksdb_options_get_read_io_executor_threads(self.inner) }
6532    }
6533
6534    /// When set to a positive value, enables read-triggered compaction. An SST file is marked
6535    /// for compaction when its estimated read frequency (estimated_reads / file_size) exceeds
6536    /// this threshold. This helps reduce read amplification for hot keys by compacting
6537    /// frequently-read files.
6538    ///
6539    /// Only "collapsible" reads are counted -- lookups that return NotFound (bloom filter
6540    /// false positive), Delete/SingleDeletion (tombstone), or Merge (partial result). These
6541    /// are reads where the file contributed no final value and compaction would eliminate the
6542    /// wasted work.
6543    ///
6544    /// Choosing a value: the threshold balances read IO saved against the write amplification
6545    /// (WA) of an extra compaction. This assumes the block-based table format is being used,
6546    ///
6547    /// Break-even derivation (no block cache): Let r = estimated_reads / file_size  (the
6548    /// threshold) S = file_size B = block_size             (typically 4 KB) F = level fanout
6549    /// (typically ~10)
6550    ///
6551    /// Each collapsible read wastes one data-block read = B bytes of IO. Total wasted read IO
6552    /// for a file = r * S * B.
6553    ///
6554    /// Compaction cost: one level-L file overlaps ~F files in level L+1, so we read (1 + F)
6555    /// files and write (1 + F) files. Total compaction IO = 2 * (1 + F) * S.
6556    ///
6557    /// Break-even when wasted read IO equals compaction IO: r * S * B = 2 * (1 + F) * S r = 2
6558    /// * (1 + F) / B
6559    ///
6560    /// With F = 10, B = 4096:  r = 22 / 4096 ~= 0.005.
6561    ///
6562    /// With a block-cache hit rate h (0 <= h < 1), each collapsible read only costs (1 - h) *
6563    /// B bytes of actual disk IO, so: r = 2 * (1 + F) / ((1 - h) * B)
6564    ///
6565    /// h = 0   -> r ~= 0.005 h = 0.5 -> r ~= 0.01 h = 0.9 -> r ~= 0.05
6566    ///
6567    /// A recommended starting point is 0.01, which avoids triggering compactions that cost
6568    /// more IO than they save for most cache-friendly workloads, while still being responsive
6569    /// enough to compact files with significant wasted reads.
6570    ///
6571    /// For this feature to take effect on a "quiet" DB (no writes), the DB-level option
6572    /// `max_compaction_trigger_wakeup_seconds` must also be set to a non-zero value so the
6573    /// periodic background job can re-evaluate files.
6574    ///
6575    /// Valid range: >= 0.0 (must be finite). Use 0.0 to disable.
6576    ///
6577    /// Dynamically changeable through SetOptions() API
6578    pub fn set_read_triggered_compaction_threshold(&mut self, val: f64) {
6579        unsafe {
6580            ffi::rocksdb_options_set_read_triggered_compaction_threshold(self.inner, val);
6581        }
6582    }
6583
6584    /// Returns the value of the `read_triggered_compaction_threshold` option.
6585    pub fn get_read_triggered_compaction_threshold(&self) -> f64 {
6586        unsafe { ffi::rocksdb_options_get_read_triggered_compaction_threshold(self.inner) }
6587    }
6588
6589    /// Sets the `remove` option.
6590    pub fn set_remove(&mut self, val: c_int) {
6591        unsafe {
6592            ffi::rocksdb_options_calculate_sst_write_lifetime_hint_set_remove(self.inner, val);
6593        }
6594    }
6595
6596    /// EXPERIMENTAL: If true, DB::Open can try to reuse the existing MANIFEST for the first
6597    /// post-open metadata update instead of creating a fresh one. This can reduce warm-open
6598    /// latency for DBs whose MANIFEST is expensive to rebuild.
6599    ///
6600    /// Best-effort optimization: even when enabled, RocksDB may still create a fresh MANIFEST
6601    /// if the FileSystem does not support reopening the existing MANIFEST for append, or if
6602    /// RocksDB decides reuse is unsafe. That fallback is normal behavior.
6603    ///
6604    /// With very small `max_manifest_file_size` settings, the reused MANIFEST can still
6605    /// rotate earlier than expected after open, because RocksDB may keep a conservative
6606    /// auto-tuned rotation threshold until it later refreshes its compacted-size estimate.
6607    ///
6608    /// Temporary rollout / kill switch while this optimization is being validated.
6609    pub fn set_reuse_manifest_on_open(&mut self, val: bool) {
6610        unsafe {
6611            ffi::rocksdb_options_set_reuse_manifest_on_open(self.inner, c_uchar::from(val));
6612        }
6613    }
6614
6615    /// Returns the value of the `reuse_manifest_on_open` option.
6616    pub fn get_reuse_manifest_on_open(&self) -> bool {
6617        unsafe { ffi::rocksdb_options_get_reuse_manifest_on_open(self.inner) != 0 }
6618    }
6619
6620    /// If this option is set then 1 in N blocks are compressed using a fast (lz4) and slow
6621    /// (zstd) compression algorithm. The compressibility is reported as stats and the stored
6622    /// data is left uncompressed (unless compression is also requested).
6623    pub fn set_sample_for_compression(&mut self, val: u64) {
6624        unsafe {
6625            ffi::rocksdb_options_set_sample_for_compression(self.inner, val);
6626        }
6627    }
6628
6629    /// Returns the value of the `sample_for_compression` option.
6630    pub fn get_sample_for_compression(&self) -> u64 {
6631        unsafe { ffi::rocksdb_options_get_sample_for_compression(self.inner) }
6632    }
6633
6634    /// if not zero, periodically take stats snapshots and store in memory, the memory size
6635    /// for stats snapshots is capped at stats_history_buffer_size Default: 1MB
6636    pub fn set_stats_history_buffer_size(&mut self, val: usize) {
6637        unsafe {
6638            ffi::rocksdb_options_set_stats_history_buffer_size(self.inner, val);
6639        }
6640    }
6641
6642    /// Returns the value of the `stats_history_buffer_size` option.
6643    pub fn get_stats_history_buffer_size(&self) -> usize {
6644        unsafe { ffi::rocksdb_options_get_stats_history_buffer_size(self.inner) }
6645    }
6646
6647    /// When true, guarantees WAL files have at most `wal_bytes_per_sync` bytes submitted for
6648    /// writeback at any given time, and SST files have at most `bytes_per_sync` bytes pending
6649    /// writeback at any given time. This can be used to handle cases where processing speed
6650    /// exceeds I/O speed during file generation, which can lead to a huge sync when the file
6651    /// is finished, even with `bytes_per_sync` / `wal_bytes_per_sync` properly configured.
6652    ///
6653    /// - If `sync_file_range` is supported it achieves this by waiting for any prior
6654    ///   `sync_file_range`s to finish before proceeding. In this way, processing
6655    ///   (compression, etc.) can proceed uninhibited in the gap between `sync_file_range`s,
6656    ///   and we block only when I/O falls behind.
6657    /// - Otherwise the `WritableFile::Sync` method is used. Note this mechanism always
6658    ///   blocks, thus preventing the interleaving of I/O and processing.
6659    ///
6660    /// Note: Enabling this option does not provide any additional persistence guarantees, as
6661    /// it may use `sync_file_range`, which does not write out metadata.
6662    ///
6663    /// Default: false
6664    pub fn set_strict_bytes_per_sync(&mut self, val: bool) {
6665        unsafe {
6666            ffi::rocksdb_options_set_strict_bytes_per_sync(self.inner, c_uchar::from(val));
6667        }
6668    }
6669
6670    /// Returns the value of the `strict_bytes_per_sync` option.
6671    pub fn get_strict_bytes_per_sync(&self) -> bool {
6672        unsafe { ffi::rocksdb_options_get_strict_bytes_per_sync(self.inner) != 0 }
6673    }
6674
6675    /// Whether to allow filesystem reads to stay under the `max_successive_merges` limit.
6676    /// When true, this can lead to merge writes blocking the write path waiting on filesystem
6677    /// reads.
6678    ///
6679    /// This option is temporary in case the recent change to disallow filesystem reads during
6680    /// merge writes has a problem and users need to undo it quickly.
6681    ///
6682    /// Default: false
6683    pub fn set_strict_max_successive_merges(&mut self, val: bool) {
6684        unsafe {
6685            ffi::rocksdb_options_set_strict_max_successive_merges(self.inner, c_uchar::from(val));
6686        }
6687    }
6688
6689    /// Returns the value of the `strict_max_successive_merges` option.
6690    pub fn get_strict_max_successive_merges(&self) -> bool {
6691        unsafe { ffi::rocksdb_options_get_strict_max_successive_merges(self.inner) != 0 }
6692    }
6693
6694    /// If true, RocksDB will consider the estimated tail size (filter + index + meta blocks)
6695    /// when deciding whether to cut a compaction output file. This helps prevent output files
6696    /// from exceeding the target_file_size_base due to large tail blocks. When disabled, only
6697    /// the data block size is considered, which may result in SST files exceeding the
6698    /// target_file_size_base.
6699    ///
6700    /// Default: false
6701    ///
6702    /// Dynamically changeable through SetOptions() API
6703    pub fn set_target_file_size_is_upper_bound(&mut self, val: bool) {
6704        unsafe {
6705            ffi::rocksdb_options_set_target_file_size_is_upper_bound(
6706                self.inner,
6707                c_uchar::from(val),
6708            );
6709        }
6710    }
6711
6712    /// Returns the value of the `target_file_size_is_upper_bound` option.
6713    pub fn get_target_file_size_is_upper_bound(&self) -> bool {
6714        unsafe { ffi::rocksdb_options_get_target_file_size_is_upper_bound(self.inner) != 0 }
6715    }
6716
6717    /// EXPERIMENTAL
6718    ///
6719    /// If true, each new WAL will record various information about its predecessor WAL for
6720    /// verification on the predecessor WAL during WAL recovery.
6721    ///
6722    /// It verifies the following:
6723    /// - There exists at least some WAL in the DB
6724    /// - It's not compatible with `RepairDB()` since this option imposes a stricter
6725    ///   requirement on WAL than the DB went through `RepariDB()` can normally meet
6726    /// - There exists no WAL hole where new WAL data presents while some old WAL data not
6727    ///   yet obsolete is missing. The DB manifest indicates which WALs are obsolete.
6728    ///
6729    /// This is intended to be a better replacement to `track_and_verify_wals_in_manifest`.
6730    ///
6731    /// Default: false
6732    pub fn set_track_and_verify_wals(&mut self, val: bool) {
6733        unsafe {
6734            ffi::rocksdb_options_set_track_and_verify_wals(self.inner, c_uchar::from(val));
6735        }
6736    }
6737
6738    /// Returns the value of the `track_and_verify_wals` option.
6739    pub fn get_track_and_verify_wals(&self) -> bool {
6740        unsafe { ffi::rocksdb_options_get_track_and_verify_wals(self.inner) != 0 }
6741    }
6742
6743    /// If enabled it uses two queues for writes, one for the ones with disable_memtable and
6744    /// one for the ones that also write to memtable. This allows the memtable writes not to
6745    /// lag behind other writes. It can be used to optimize MySQL 2PC in which only the
6746    /// commits, which are serial, write to memtable.
6747    pub fn set_two_write_queues(&mut self, val: bool) {
6748        unsafe {
6749            ffi::rocksdb_options_set_two_write_queues(self.inner, c_uchar::from(val));
6750        }
6751    }
6752
6753    /// Returns the value of the `two_write_queues` option.
6754    pub fn get_two_write_queues(&self) -> bool {
6755        unsafe { ffi::rocksdb_options_get_two_write_queues(self.inner) != 0 }
6756    }
6757
6758    /// EXPERIMENTAL When > 0, RocksDB attempts to erase some block cache entries for files
6759    /// that have become obsolete, which means they are about to be deleted. To avoid
6760    /// excessive tracking, this "uncaching" process is iterative and speculative, meaning it
6761    /// could incur extra background CPU effort if the file's blocks are generally not cached.
6762    /// A larger number indicates more willingness to spend CPU time to maximize block cache
6763    /// hit rates by erasing known-obsolete entries.
6764    ///
6765    /// When uncache_aggressiveness=1, block cache entries for an obsolete file are only
6766    /// erased until any attempted erase operation fails because the block is not cached. Then
6767    /// no further attempts are made to erase cached blocks for that file.
6768    ///
6769    /// For larger values, erasure is attempted until evidence incidates that the chance of
6770    /// success is < 0.99^(a-1), where a = uncache_aggressiveness. For example: 2 -> Attempt
6771    /// only while expecting >= 99% successful/useful erasure 11 -> 90% 69 -> 50% 110 -> 33%
6772    /// 230 -> 10% 460 -> 1% 690 -> 0.1% 1000 -> 1 in 23000 10000 -> Always (for all practical
6773    /// purposes) NOTE: UINT32_MAX and nearby values could take additional special meanings in
6774    /// the future.
6775    ///
6776    /// Pinned cache entries (guaranteed present) are always erased if uncache_aggressiveness
6777    /// \> 0, but are not used in predicting the chances of successful erasure of non-pinned
6778    /// entries.
6779    ///
6780    /// NOTE: In the case of copied DBs (such as Checkpoints) sharing a block cache, it is
6781    /// possible that a file becoming obsolete doesn't mean its block cache entries (shared
6782    /// among copies) are obsolete. Such a scenerio is the best case for
6783    /// uncache_aggressiveness = 0.
6784    ///
6785    /// When using allow_mmap_reads=true, this option is ignored (no un-caching).
6786    ///
6787    /// Once validated in production, the default will likely change to something around 300.
6788    pub fn set_uncache_aggressiveness(&mut self, val: u32) {
6789        unsafe {
6790            ffi::rocksdb_options_set_uncache_aggressiveness(self.inner, val);
6791        }
6792    }
6793
6794    /// Returns the value of the `uncache_aggressiveness` option.
6795    pub fn get_uncache_aggressiveness(&self) -> u32 {
6796        unsafe { ffi::rocksdb_options_get_uncache_aggressiveness(self.inner) }
6797    }
6798
6799    /// Use O_DIRECT for compaction-input SST reads only, leaving user reads buffered. Useful
6800    /// when sequential compaction reads would otherwise evict the hot user-read working set
6801    /// from the OS page cache. When this is true and use_direct_reads is false, compaction
6802    /// opens short-lived O_DIRECT readers for its input files instead of reusing the buffered
6803    /// readers cached for user reads. This is the read-side analogue of
6804    /// use_direct_io_for_flush_and_compaction, and the two are often paired on write-heavy
6805    /// workloads.
6806    ///
6807    /// Scope and limits:
6808    /// - DBOption scope (applies to all column families); no per-CF setting.
6809    /// - Covers compaction inputs only. Blob-file reads and compaction-output verification
6810    ///   (paranoid_file_checks) still use the buffered path.
6811    /// - The ephemeral readers bypass the TableCache and are not counted against
6812    ///   max_open_files. Non-L0 levels keep one reader open at a time; L0 opens all of a
6813    ///   subcompaction's overlapping inputs at once, so with large L0 fan-in and many
6814    ///   subcompactions, watch RLIMIT_NOFILE.
6815    /// - Every input file is reopened per compaction, so NO_FILE_OPENS and
6816    ///   TABLE_OPEN_IO_MICROS rise while this is enabled.
6817    ///
6818    /// The same SST can be open through both a buffered handle (user reads) and an O_DIRECT
6819    /// handle (the compaction scan) at once; modern Linux handles this fine. The flag is
6820    /// neutral or slightly negative for in-memory DBs or uniform random reads, so measure
6821    /// before enabling.
6822    ///
6823    /// Has no effect when use_direct_reads is true (all reads are already O_DIRECT). Rejected
6824    /// at DB::Open when allow_mmap_reads is set.
6825    ///
6826    /// On a filesystem without O_DIRECT support (e.g. tmpfs), DB::Open fails: it probes by
6827    /// opening the MANIFEST with O_DIRECT. The probe only checks the filesystem holding the
6828    /// DB directory, so if SST files live elsewhere (via db_paths/cf_paths) without O_DIRECT,
6829    /// Open succeeds and the first compaction fails instead.
6830    ///
6831    /// Default: false
6832    pub fn set_use_direct_io_for_compaction_reads(&mut self, val: bool) {
6833        unsafe {
6834            ffi::rocksdb_options_set_use_direct_io_for_compaction_reads(
6835                self.inner,
6836                c_uchar::from(val),
6837            );
6838        }
6839    }
6840
6841    /// Returns the value of the `use_direct_io_for_compaction_reads` option.
6842    pub fn get_use_direct_io_for_compaction_reads(&self) -> bool {
6843        unsafe { ffi::rocksdb_options_get_use_direct_io_for_compaction_reads(self.inner) != 0 }
6844    }
6845
6846    /// If true, on DB close, read back the entire MANIFEST file and validate CRC checksums
6847    /// and logical record content. If corruption is detected, a fresh MANIFEST is written
6848    /// from in-memory state before closing.
6849    ///
6850    /// This option is mutable with SetDBOptions().
6851    pub fn set_verify_manifest_content_on_close(&mut self, val: bool) {
6852        unsafe {
6853            ffi::rocksdb_options_set_verify_manifest_content_on_close(
6854                self.inner,
6855                c_uchar::from(val),
6856            );
6857        }
6858    }
6859
6860    /// Returns the value of the `verify_manifest_content_on_close` option.
6861    pub fn get_verify_manifest_content_on_close(&self) -> bool {
6862        unsafe { ffi::rocksdb_options_get_verify_manifest_content_on_close(self.inner) != 0 }
6863    }
6864
6865    /// Bitmask enum for output verification option.
6866    ///
6867    /// Default: 0 (kVerifyNone)
6868    ///
6869    /// Dynamically changeable (as a uint32_t) through SetOptions() API.
6870    pub fn set_verify_output_flags(&mut self, val: c_int) {
6871        unsafe {
6872            ffi::rocksdb_options_set_verify_output_flags(self.inner, val);
6873        }
6874    }
6875
6876    /// Returns the value of the `verify_output_flags` option.
6877    pub fn get_verify_output_flags(&self) -> c_int {
6878        unsafe { ffi::rocksdb_options_get_verify_output_flags(self.inner) }
6879    }
6880
6881    /// If true, verifies the SST unique id between MANIFEST and actual file each time an SST
6882    /// file is opened. This check ensures an SST file is not overwritten or misplaced. A
6883    /// corruption error will be reported if mismatch detected, but only when MANIFEST tracks
6884    /// the unique id, which starts from RocksDB version 7.3. Although the tracked internal
6885    /// unique id is related to the one returned by GetUniqueIdFromTableProperties, that is
6886    /// subject to change. NOTE: verification is currently only done on SST files using
6887    /// block-based table format.
6888    ///
6889    /// Setting to false should only be needed in case of unexpected problems.
6890    ///
6891    /// Although an early version of this option opened all SST files for verification on
6892    /// DB::Open, that is no longer guaranteed. However, as documented in an above option, if
6893    /// max_open_files is -1, DB will open all files on DB::Open().
6894    ///
6895    /// Default: true
6896    pub fn set_verify_sst_unique_id_in_manifest(&mut self, val: bool) {
6897        unsafe {
6898            ffi::rocksdb_options_set_verify_sst_unique_id_in_manifest(
6899                self.inner,
6900                c_uchar::from(val),
6901            );
6902        }
6903    }
6904
6905    /// Returns the value of the `verify_sst_unique_id_in_manifest` option.
6906    pub fn get_verify_sst_unique_id_in_manifest(&self) -> bool {
6907        unsafe { ffi::rocksdb_options_get_verify_sst_unique_id_in_manifest(self.inner) != 0 }
6908    }
6909
6910    /// Use this filesystem temperature when creating WAL files. When not `kUnknown`, this
6911    /// overrides any temperature set by OptimizeForLogWrite functions.
6912    pub fn set_wal_write_temperature(&mut self, val: c_int) {
6913        unsafe {
6914            ffi::rocksdb_options_set_wal_write_temperature(self.inner, val);
6915        }
6916    }
6917
6918    /// Returns the value of the `wal_write_temperature` option.
6919    pub fn get_wal_write_temperature(&self) -> c_int {
6920        unsafe { ffi::rocksdb_options_get_wal_write_temperature(self.inner) }
6921    }
6922
6923    /// The maximum number of microseconds that a write operation will use a yielding spin
6924    /// loop to coordinate with other write threads before blocking on a mutex.  (Assuming
6925    /// write_thread_slow_yield_usec is set properly) increasing this value is likely to
6926    /// increase RocksDB throughput at the expense of increased CPU usage.
6927    ///
6928    /// Default: 100
6929    pub fn set_write_thread_max_yield_usec(&mut self, val: u64) {
6930        unsafe {
6931            ffi::rocksdb_options_set_write_thread_max_yield_usec(self.inner, val);
6932        }
6933    }
6934
6935    /// Returns the value of the `write_thread_max_yield_usec` option.
6936    pub fn get_write_thread_max_yield_usec(&self) -> u64 {
6937        unsafe { ffi::rocksdb_options_get_write_thread_max_yield_usec(self.inner) }
6938    }
6939
6940    /// The latency in microseconds after which a std::this_thread::yield call (sched_yield on
6941    /// Linux) is considered to be a signal that other processes or threads would like to use
6942    /// the current core. Increasing this makes writer threads more likely to take CPU by
6943    /// spinning, which will show up as an increase in the number of involuntary context
6944    /// switches.
6945    ///
6946    /// Default: 3
6947    pub fn set_write_thread_slow_yield_usec(&mut self, val: u64) {
6948        unsafe {
6949            ffi::rocksdb_options_set_write_thread_slow_yield_usec(self.inner, val);
6950        }
6951    }
6952
6953    /// Returns the value of the `write_thread_slow_yield_usec` option.
6954    pub fn get_write_thread_slow_yield_usec(&self) -> u64 {
6955        unsafe { ffi::rocksdb_options_get_write_thread_slow_yield_usec(self.inner) }
6956    }
6957
6958    /// Returns the current `advise_random_on_open` setting.
6959    ///
6960    /// See [`Self::set_advise_random_on_open`] for what this controls.
6961    pub fn get_advise_random_on_open(&self) -> bool {
6962        unsafe { ffi::rocksdb_options_get_advise_random_on_open(self.inner) != 0 }
6963    }
6964
6965    /// Returns the current `allow_concurrent_memtable_write` setting.
6966    ///
6967    /// See [`Self::set_allow_concurrent_memtable_write`] for what this controls.
6968    pub fn get_allow_concurrent_memtable_write(&self) -> bool {
6969        unsafe { ffi::rocksdb_options_get_allow_concurrent_memtable_write(self.inner) != 0 }
6970    }
6971
6972    /// Returns the current `allow_ingest_behind` setting.
6973    ///
6974    /// See [`Self::set_allow_ingest_behind`] for what this controls.
6975    pub fn get_allow_ingest_behind(&self) -> bool {
6976        unsafe { ffi::rocksdb_options_get_allow_ingest_behind(self.inner) != 0 }
6977    }
6978
6979    /// Returns the current `allow_mmap_reads` setting.
6980    ///
6981    /// See [`Self::set_allow_mmap_reads`] for what this controls.
6982    pub fn get_allow_mmap_reads(&self) -> bool {
6983        unsafe { ffi::rocksdb_options_get_allow_mmap_reads(self.inner) != 0 }
6984    }
6985
6986    /// Returns the current `allow_mmap_writes` setting.
6987    ///
6988    /// See [`Self::set_allow_mmap_writes`] for what this controls.
6989    pub fn get_allow_mmap_writes(&self) -> bool {
6990        unsafe { ffi::rocksdb_options_get_allow_mmap_writes(self.inner) != 0 }
6991    }
6992
6993    /// Returns the current `arena_block_size` setting.
6994    ///
6995    /// See [`Self::set_arena_block_size`] for what this controls.
6996    pub fn get_arena_block_size(&self) -> usize {
6997        unsafe { ffi::rocksdb_options_get_arena_block_size(self.inner) }
6998    }
6999
7000    /// Returns the current `atomic_flush` setting.
7001    ///
7002    /// See [`Self::set_atomic_flush`] for what this controls.
7003    pub fn get_atomic_flush(&self) -> bool {
7004        unsafe { ffi::rocksdb_options_get_atomic_flush(self.inner) != 0 }
7005    }
7006
7007    /// Returns the current `avoid_unnecessary_blocking_io` setting.
7008    ///
7009    /// See [`Self::set_avoid_unnecessary_blocking_io`] for what this controls.
7010    pub fn get_avoid_unnecessary_blocking_io(&self) -> bool {
7011        unsafe { ffi::rocksdb_options_get_avoid_unnecessary_blocking_io(self.inner) != 0 }
7012    }
7013
7014    /// Returns the current `blob_compaction_readahead_size` setting.
7015    ///
7016    /// See [`Self::set_blob_compaction_readahead_size`] for what this controls.
7017    pub fn get_blob_compaction_readahead_size(&self) -> u64 {
7018        unsafe { ffi::rocksdb_options_get_blob_compaction_readahead_size(self.inner) }
7019    }
7020
7021    /// Returns the current `blob_file_size` setting.
7022    ///
7023    /// See [`Self::set_blob_file_size`] for what this controls.
7024    pub fn get_blob_file_size(&self) -> u64 {
7025        unsafe { ffi::rocksdb_options_get_blob_file_size(self.inner) }
7026    }
7027
7028    /// Returns the current `blob_file_starting_level` setting.
7029    ///
7030    /// See [`Self::set_blob_file_starting_level`] for what this controls.
7031    pub fn get_blob_file_starting_level(&self) -> c_int {
7032        unsafe { ffi::rocksdb_options_get_blob_file_starting_level(self.inner) }
7033    }
7034
7035    /// Returns the current `blob_gc_age_cutoff` setting.
7036    ///
7037    /// See [`Self::set_blob_gc_age_cutoff`] for what this controls.
7038    pub fn get_blob_gc_age_cutoff(&self) -> f64 {
7039        unsafe { ffi::rocksdb_options_get_blob_gc_age_cutoff(self.inner) }
7040    }
7041
7042    /// Returns the current `blob_gc_force_threshold` setting.
7043    ///
7044    /// See [`Self::set_blob_gc_force_threshold`] for what this controls.
7045    pub fn get_blob_gc_force_threshold(&self) -> f64 {
7046        unsafe { ffi::rocksdb_options_get_blob_gc_force_threshold(self.inner) }
7047    }
7048
7049    /// Returns the current `bloom_locality` setting.
7050    ///
7051    /// See [`Self::set_bloom_locality`] for what this controls.
7052    pub fn get_bloom_locality(&self) -> u32 {
7053        unsafe { ffi::rocksdb_options_get_bloom_locality(self.inner) }
7054    }
7055
7056    /// Returns the current `bottommost_compression_options_use_zstd_dict_trainer` setting.
7057    ///
7058    /// See [`Self::set_bottommost_compression_options_use_zstd_dict_trainer`] for what this controls.
7059    pub fn get_bottommost_compression_options_use_zstd_dict_trainer(&self) -> bool {
7060        unsafe {
7061            ffi::rocksdb_options_get_bottommost_compression_options_use_zstd_dict_trainer(
7062                self.inner,
7063            ) != 0
7064        }
7065    }
7066
7067    /// Returns the current `bytes_per_sync` setting.
7068    ///
7069    /// See [`Self::set_bytes_per_sync`] for what this controls.
7070    pub fn get_bytes_per_sync(&self) -> u64 {
7071        unsafe { ffi::rocksdb_options_get_bytes_per_sync(self.inner) }
7072    }
7073
7074    /// Returns the current `compaction_readahead_size` setting.
7075    ///
7076    /// See [`Self::set_compaction_readahead_size`] for what this controls.
7077    pub fn get_compaction_readahead_size(&self) -> usize {
7078        unsafe { ffi::rocksdb_options_get_compaction_readahead_size(self.inner) }
7079    }
7080
7081    /// Returns the current `compression_options_max_dict_buffer_bytes` setting.
7082    ///
7083    /// See [`Self::set_compression_options_max_dict_buffer_bytes`] for what this controls.
7084    pub fn get_compression_options_max_dict_buffer_bytes(&self) -> u64 {
7085        unsafe { ffi::rocksdb_options_get_compression_options_max_dict_buffer_bytes(self.inner) }
7086    }
7087
7088    /// Returns the current `compression_options_parallel_threads` setting.
7089    ///
7090    /// See [`Self::set_compression_options_parallel_threads`] for what this controls.
7091    pub fn get_compression_options_parallel_threads(&self) -> c_int {
7092        unsafe { ffi::rocksdb_options_get_compression_options_parallel_threads(self.inner) }
7093    }
7094
7095    /// Returns the current `compression_options_use_zstd_dict_trainer` setting.
7096    ///
7097    /// See [`Self::set_compression_options_use_zstd_dict_trainer`] for what this controls.
7098    pub fn get_compression_options_use_zstd_dict_trainer(&self) -> bool {
7099        unsafe {
7100            ffi::rocksdb_options_get_compression_options_use_zstd_dict_trainer(self.inner) != 0
7101        }
7102    }
7103
7104    /// Returns the maximum size of training data passed to zstd's dictionary trainer.
7105    pub fn get_compression_options_zstd_max_train_bytes(&self) -> c_int {
7106        unsafe { ffi::rocksdb_options_get_compression_options_zstd_max_train_bytes(self.inner) }
7107    }
7108
7109    /// Returns the current `create_if_missing` setting.
7110    ///
7111    /// See [`Self::create_if_missing`] for what this controls.
7112    pub fn get_create_if_missing(&self) -> bool {
7113        unsafe { ffi::rocksdb_options_get_create_if_missing(self.inner) != 0 }
7114    }
7115
7116    /// Returns the current `create_missing_column_families` setting.
7117    ///
7118    /// See [`Self::create_missing_column_families`] for what this controls.
7119    pub fn get_create_missing_column_families(&self) -> bool {
7120        unsafe { ffi::rocksdb_options_get_create_missing_column_families(self.inner) != 0 }
7121    }
7122
7123    /// Returns the current `db_write_buffer_size` setting.
7124    ///
7125    /// See [`Self::set_db_write_buffer_size`] for what this controls.
7126    pub fn get_db_write_buffer_size(&self) -> usize {
7127        unsafe { ffi::rocksdb_options_get_db_write_buffer_size(self.inner) }
7128    }
7129
7130    /// Returns the current `delete_obsolete_files_period_micros` setting.
7131    ///
7132    /// See [`Self::set_delete_obsolete_files_period_micros`] for what this controls.
7133    pub fn get_delete_obsolete_files_period_micros(&self) -> u64 {
7134        unsafe { ffi::rocksdb_options_get_delete_obsolete_files_period_micros(self.inner) }
7135    }
7136
7137    /// Returns the current `disable_auto_compactions` setting.
7138    ///
7139    /// See [`Self::set_disable_auto_compactions`] for what this controls.
7140    pub fn get_disable_auto_compactions(&self) -> bool {
7141        unsafe { ffi::rocksdb_options_get_disable_auto_compactions(self.inner) != 0 }
7142    }
7143
7144    /// Returns the current `enable_blob_files` setting.
7145    ///
7146    /// See [`Self::set_enable_blob_files`] for what this controls.
7147    pub fn get_enable_blob_files(&self) -> bool {
7148        unsafe { ffi::rocksdb_options_get_enable_blob_files(self.inner) != 0 }
7149    }
7150
7151    /// Returns the current `enable_blob_gc` setting.
7152    ///
7153    /// See [`Self::set_enable_blob_gc`] for what this controls.
7154    pub fn get_enable_blob_gc(&self) -> bool {
7155        unsafe { ffi::rocksdb_options_get_enable_blob_gc(self.inner) != 0 }
7156    }
7157
7158    /// Returns the current `enable_pipelined_write` setting.
7159    ///
7160    /// See [`Self::set_enable_pipelined_write`] for what this controls.
7161    pub fn get_enable_pipelined_write(&self) -> bool {
7162        unsafe { ffi::rocksdb_options_get_enable_pipelined_write(self.inner) != 0 }
7163    }
7164
7165    /// Returns the current `enable_write_thread_adaptive_yield` setting.
7166    ///
7167    /// See [`Self::set_enable_write_thread_adaptive_yield`] for what this controls.
7168    pub fn get_enable_write_thread_adaptive_yield(&self) -> bool {
7169        unsafe { ffi::rocksdb_options_get_enable_write_thread_adaptive_yield(self.inner) != 0 }
7170    }
7171
7172    /// Returns the current `error_if_exists` setting.
7173    ///
7174    /// See [`Self::set_error_if_exists`] for what this controls.
7175    pub fn get_error_if_exists(&self) -> bool {
7176        unsafe { ffi::rocksdb_options_get_error_if_exists(self.inner) != 0 }
7177    }
7178
7179    /// Returns the current `experimental_mempurge_threshold` setting.
7180    ///
7181    /// See [`Self::set_experimental_mempurge_threshold`] for what this controls.
7182    pub fn get_experimental_mempurge_threshold(&self) -> f64 {
7183        unsafe { ffi::rocksdb_options_get_experimental_mempurge_threshold(self.inner) }
7184    }
7185
7186    /// Returns the current `hard_pending_compaction_bytes_limit` setting.
7187    ///
7188    /// See [`Self::set_hard_pending_compaction_bytes_limit`] for what this controls.
7189    pub fn get_hard_pending_compaction_bytes_limit(&self) -> usize {
7190        unsafe { ffi::rocksdb_options_get_hard_pending_compaction_bytes_limit(self.inner) }
7191    }
7192
7193    /// Number of locks used for inplace update Default: 10000, if inplace_update_support =
7194    /// true, else 0.
7195    ///
7196    /// Dynamically changeable through SetOptions() API.
7197    pub fn get_inplace_update_num_locks(&self) -> usize {
7198        unsafe { ffi::rocksdb_options_get_inplace_update_num_locks(self.inner) }
7199    }
7200
7201    /// Returns the current `inplace_update_support` setting.
7202    ///
7203    /// See [`Self::set_inplace_update_support`] for what this controls.
7204    pub fn get_inplace_update_support(&self) -> bool {
7205        unsafe { ffi::rocksdb_options_get_inplace_update_support(self.inner) != 0 }
7206    }
7207
7208    /// Returns the current `is_fd_close_on_exec` setting.
7209    ///
7210    /// See [`Self::set_is_fd_close_on_exec`] for what this controls.
7211    pub fn get_is_fd_close_on_exec(&self) -> bool {
7212        unsafe { ffi::rocksdb_options_get_is_fd_close_on_exec(self.inner) != 0 }
7213    }
7214
7215    /// Returns the current `keep_log_file_num` setting.
7216    ///
7217    /// See [`Self::set_keep_log_file_num`] for what this controls.
7218    pub fn get_keep_log_file_num(&self) -> usize {
7219        unsafe { ffi::rocksdb_options_get_keep_log_file_num(self.inner) }
7220    }
7221
7222    /// Number of files to trigger level-0 compaction. A value <0 means that level-0
7223    /// compaction will not be triggered by number of files at all.
7224    ///
7225    /// Universal compaction: RocksDB will try to keep the number of sorted runs no more than
7226    /// this number. If CompactionOptionsUniversal::max_read_amp is set, then this option will
7227    /// be used only as a trigger to look for compaction.
7228    /// CompactionOptionsUniversal::max_read_amp will be the limit on the number of sorted
7229    /// runs.
7230    ///
7231    /// Default: 4
7232    ///
7233    /// Dynamically changeable through SetOptions() API.
7234    pub fn get_level0_file_num_compaction_trigger(&self) -> c_int {
7235        unsafe { ffi::rocksdb_options_get_level0_file_num_compaction_trigger(self.inner) }
7236    }
7237
7238    /// Soft limit on number of level-0 files. We start slowing down writes at this point. A
7239    /// value <0 means that no writing slow down will be triggered by number of files in
7240    /// level-0.
7241    ///
7242    /// Default: 20
7243    ///
7244    /// Dynamically changeable through SetOptions() API.
7245    pub fn get_level0_slowdown_writes_trigger(&self) -> c_int {
7246        unsafe { ffi::rocksdb_options_get_level0_slowdown_writes_trigger(self.inner) }
7247    }
7248
7249    /// Maximum number of level-0 files.  We stop writes at this point.
7250    ///
7251    /// Default: 36
7252    ///
7253    /// Dynamically changeable through SetOptions() API.
7254    pub fn get_level0_stop_writes_trigger(&self) -> c_int {
7255        unsafe { ffi::rocksdb_options_get_level0_stop_writes_trigger(self.inner) }
7256    }
7257
7258    /// Returns the current `level_compaction_dynamic_level_bytes` setting.
7259    ///
7260    /// See [`Self::set_level_compaction_dynamic_level_bytes`] for what this controls.
7261    pub fn get_level_compaction_dynamic_level_bytes(&self) -> bool {
7262        unsafe { ffi::rocksdb_options_get_level_compaction_dynamic_level_bytes(self.inner) != 0 }
7263    }
7264
7265    /// Returns the current `log_file_time_to_roll` setting.
7266    ///
7267    /// See [`Self::set_log_file_time_to_roll`] for what this controls.
7268    pub fn get_log_file_time_to_roll(&self) -> usize {
7269        unsafe { ffi::rocksdb_options_get_log_file_time_to_roll(self.inner) }
7270    }
7271
7272    /// Returns the current `manifest_preallocation_size` setting.
7273    ///
7274    /// See [`Self::set_manifest_preallocation_size`] for what this controls.
7275    pub fn get_manifest_preallocation_size(&self) -> usize {
7276        unsafe { ffi::rocksdb_options_get_manifest_preallocation_size(self.inner) }
7277    }
7278
7279    /// Returns the current `manual_wal_flush` setting.
7280    ///
7281    /// See [`Self::set_manual_wal_flush`] for what this controls.
7282    pub fn get_manual_wal_flush(&self) -> bool {
7283        unsafe { ffi::rocksdb_options_get_manual_wal_flush(self.inner) != 0 }
7284    }
7285
7286    /// Returns the current `max_background_jobs` setting.
7287    ///
7288    /// See [`Self::set_max_background_jobs`] for what this controls.
7289    pub fn get_max_background_jobs(&self) -> c_int {
7290        unsafe { ffi::rocksdb_options_get_max_background_jobs(self.inner) }
7291    }
7292
7293    /// Returns the current `max_bytes_for_level_base` setting.
7294    ///
7295    /// See [`Self::set_max_bytes_for_level_base`] for what this controls.
7296    pub fn get_max_bytes_for_level_base(&self) -> u64 {
7297        unsafe { ffi::rocksdb_options_get_max_bytes_for_level_base(self.inner) }
7298    }
7299
7300    /// Returns the current `max_bytes_for_level_multiplier` setting.
7301    ///
7302    /// See [`Self::set_max_bytes_for_level_multiplier`] for what this controls.
7303    pub fn get_max_bytes_for_level_multiplier(&self) -> f64 {
7304        unsafe { ffi::rocksdb_options_get_max_bytes_for_level_multiplier(self.inner) }
7305    }
7306
7307    /// Returns the current `max_compaction_bytes` setting.
7308    ///
7309    /// See [`Self::set_max_compaction_bytes`] for what this controls.
7310    pub fn get_max_compaction_bytes(&self) -> u64 {
7311        unsafe { ffi::rocksdb_options_get_max_compaction_bytes(self.inner) }
7312    }
7313
7314    /// Returns the current `max_file_opening_threads` setting.
7315    ///
7316    /// See [`Self::set_max_file_opening_threads`] for what this controls.
7317    pub fn get_max_file_opening_threads(&self) -> c_int {
7318        unsafe { ffi::rocksdb_options_get_max_file_opening_threads(self.inner) }
7319    }
7320
7321    /// Returns the current `max_log_file_size` setting.
7322    ///
7323    /// See [`Self::set_max_log_file_size`] for what this controls.
7324    pub fn get_max_log_file_size(&self) -> usize {
7325        unsafe { ffi::rocksdb_options_get_max_log_file_size(self.inner) }
7326    }
7327
7328    /// Returns the current `max_manifest_file_size` setting.
7329    ///
7330    /// See [`Self::set_max_manifest_file_size`] for what this controls.
7331    pub fn get_max_manifest_file_size(&self) -> usize {
7332        unsafe { ffi::rocksdb_options_get_max_manifest_file_size(self.inner) }
7333    }
7334
7335    /// Returns the current `max_open_files` setting.
7336    ///
7337    /// See [`Self::set_max_open_files`] for what this controls.
7338    pub fn get_max_open_files(&self) -> c_int {
7339        unsafe { ffi::rocksdb_options_get_max_open_files(self.inner) }
7340    }
7341
7342    /// Returns the current `max_sequential_skip_in_iterations` setting.
7343    ///
7344    /// See [`Self::set_max_sequential_skip_in_iterations`] for what this controls.
7345    pub fn get_max_sequential_skip_in_iterations(&self) -> u64 {
7346        unsafe { ffi::rocksdb_options_get_max_sequential_skip_in_iterations(self.inner) }
7347    }
7348
7349    /// Returns the current `max_subcompactions` setting.
7350    ///
7351    /// See [`Self::set_max_subcompactions`] for what this controls.
7352    pub fn get_max_subcompactions(&self) -> u32 {
7353        unsafe { ffi::rocksdb_options_get_max_subcompactions(self.inner) }
7354    }
7355
7356    /// Returns the current `max_successive_merges` setting.
7357    ///
7358    /// See [`Self::set_max_successive_merges`] for what this controls.
7359    pub fn get_max_successive_merges(&self) -> usize {
7360        unsafe { ffi::rocksdb_options_get_max_successive_merges(self.inner) }
7361    }
7362
7363    /// Returns the current `max_total_wal_size` setting.
7364    ///
7365    /// See [`Self::set_max_total_wal_size`] for what this controls.
7366    pub fn get_max_total_wal_size(&self) -> u64 {
7367        unsafe { ffi::rocksdb_options_get_max_total_wal_size(self.inner) }
7368    }
7369
7370    /// Returns the current `max_write_buffer_number` setting.
7371    ///
7372    /// See [`Self::set_max_write_buffer_number`] for what this controls.
7373    pub fn get_max_write_buffer_number(&self) -> c_int {
7374        unsafe { ffi::rocksdb_options_get_max_write_buffer_number(self.inner) }
7375    }
7376
7377    /// Returns the current `max_write_buffer_size_to_maintain` setting.
7378    ///
7379    /// See [`Self::set_max_write_buffer_size_to_maintain`] for what this controls.
7380    pub fn get_max_write_buffer_size_to_maintain(&self) -> i64 {
7381        unsafe { ffi::rocksdb_options_get_max_write_buffer_size_to_maintain(self.inner) }
7382    }
7383
7384    /// Returns the current `memtable_avg_op_scan_flush_trigger` setting.
7385    ///
7386    /// See [`Self::set_memtable_avg_op_scan_flush_trigger`] for what this controls.
7387    pub fn get_memtable_avg_op_scan_flush_trigger(&self) -> u32 {
7388        unsafe { ffi::rocksdb_options_get_memtable_avg_op_scan_flush_trigger(self.inner) }
7389    }
7390
7391    /// Returns the current `memtable_huge_page_size` setting.
7392    ///
7393    /// See [`Self::set_memtable_huge_page_size`] for what this controls.
7394    pub fn get_memtable_huge_page_size(&self) -> usize {
7395        unsafe { ffi::rocksdb_options_get_memtable_huge_page_size(self.inner) }
7396    }
7397
7398    /// Returns the current `memtable_op_scan_flush_trigger` setting.
7399    ///
7400    /// See [`Self::set_memtable_op_scan_flush_trigger`] for what this controls.
7401    pub fn get_memtable_op_scan_flush_trigger(&self) -> u32 {
7402        unsafe { ffi::rocksdb_options_get_memtable_op_scan_flush_trigger(self.inner) }
7403    }
7404
7405    /// Should really be called `memtable_bloom_size_ratio`. Enables a dynamic Bloom filter in
7406    /// memtable to optimize many queries that must go beyond the memtable. The size in bytes
7407    /// of the filter is write_buffer_size * memtable_prefix_bloom_size_ratio.
7408    /// - If prefix_extractor is set, the filter includes prefixes.
7409    /// - If memtable_whole_key_filtering, the filter includes whole keys.
7410    /// - If both, the filter includes both.
7411    /// - If neither, the feature is disabled.
7412    ///
7413    /// If this value is larger than 0.25, it is sanitized to 0.25.
7414    ///
7415    /// Default: 0 (disabled)
7416    ///
7417    /// Dynamically changeable through SetOptions() API.
7418    pub fn get_memtable_prefix_bloom_size_ratio(&self) -> f64 {
7419        unsafe { ffi::rocksdb_options_get_memtable_prefix_bloom_size_ratio(self.inner) }
7420    }
7421
7422    /// Returns the current `min_blob_size` setting.
7423    ///
7424    /// See [`Self::set_min_blob_size`] for what this controls.
7425    pub fn get_min_blob_size(&self) -> u64 {
7426        unsafe { ffi::rocksdb_options_get_min_blob_size(self.inner) }
7427    }
7428
7429    /// Returns the current `min_write_buffer_number_to_merge` setting.
7430    ///
7431    /// See [`Self::set_min_write_buffer_number_to_merge`] for what this controls.
7432    pub fn get_min_write_buffer_number_to_merge(&self) -> c_int {
7433        unsafe { ffi::rocksdb_options_get_min_write_buffer_number_to_merge(self.inner) }
7434    }
7435
7436    /// Returns the current `num_levels` setting.
7437    ///
7438    /// See [`Self::set_num_levels`] for what this controls.
7439    pub fn get_num_levels(&self) -> c_int {
7440        unsafe { ffi::rocksdb_options_get_num_levels(self.inner) }
7441    }
7442
7443    /// Returns the current `optimize_filters_for_hits` setting.
7444    ///
7445    /// See [`Self::set_optimize_filters_for_hits`] for what this controls.
7446    pub fn get_optimize_filters_for_hits(&self) -> bool {
7447        unsafe { ffi::rocksdb_options_get_optimize_filters_for_hits(self.inner) != 0 }
7448    }
7449
7450    /// Returns the current `paranoid_checks` setting.
7451    ///
7452    /// See [`Self::set_paranoid_checks`] for what this controls.
7453    pub fn get_paranoid_checks(&self) -> bool {
7454        unsafe { ffi::rocksdb_options_get_paranoid_checks(self.inner) != 0 }
7455    }
7456
7457    /// Returns the current `periodic_compaction_seconds` setting.
7458    ///
7459    /// See [`Self::set_periodic_compaction_seconds`] for what this controls.
7460    pub fn get_periodic_compaction_seconds(&self) -> u64 {
7461        unsafe { ffi::rocksdb_options_get_periodic_compaction_seconds(self.inner) }
7462    }
7463
7464    /// Returns the current `recycle_log_file_num` setting.
7465    ///
7466    /// See [`Self::set_recycle_log_file_num`] for what this controls.
7467    pub fn get_recycle_log_file_num(&self) -> usize {
7468        unsafe { ffi::rocksdb_options_get_recycle_log_file_num(self.inner) }
7469    }
7470
7471    /// Returns the current `report_bg_io_stats` setting.
7472    ///
7473    /// See [`Self::set_report_bg_io_stats`] for what this controls.
7474    pub fn get_report_bg_io_stats(&self) -> bool {
7475        unsafe { ffi::rocksdb_options_get_report_bg_io_stats(self.inner) != 0 }
7476    }
7477
7478    /// Returns the current `skip_stats_update_on_db_open` setting.
7479    ///
7480    /// See [`Self::set_skip_stats_update_on_db_open`] for what this controls.
7481    pub fn get_skip_stats_update_on_db_open(&self) -> bool {
7482        unsafe { ffi::rocksdb_options_get_skip_stats_update_on_db_open(self.inner) != 0 }
7483    }
7484
7485    /// Returns the current `soft_pending_compaction_bytes_limit` setting.
7486    ///
7487    /// See [`Self::set_soft_pending_compaction_bytes_limit`] for what this controls.
7488    pub fn get_soft_pending_compaction_bytes_limit(&self) -> usize {
7489        unsafe { ffi::rocksdb_options_get_soft_pending_compaction_bytes_limit(self.inner) }
7490    }
7491
7492    /// Returns the current `stats_dump_period_sec` setting.
7493    ///
7494    /// See [`Self::set_stats_dump_period_sec`] for what this controls.
7495    pub fn get_stats_dump_period_sec(&self) -> u32 {
7496        unsafe { ffi::rocksdb_options_get_stats_dump_period_sec(self.inner) }
7497    }
7498
7499    /// Returns the current `stats_persist_period_sec` setting.
7500    ///
7501    /// See [`Self::set_stats_persist_period_sec`] for what this controls.
7502    pub fn get_stats_persist_period_sec(&self) -> u32 {
7503        unsafe { ffi::rocksdb_options_get_stats_persist_period_sec(self.inner) }
7504    }
7505
7506    /// Number of shards used for table cache.
7507    pub fn get_table_cache_numshardbits(&self) -> c_int {
7508        unsafe { ffi::rocksdb_options_get_table_cache_numshardbits(self.inner) }
7509    }
7510
7511    /// Returns the current `target_file_size_base` setting.
7512    ///
7513    /// See [`Self::set_target_file_size_base`] for what this controls.
7514    pub fn get_target_file_size_base(&self) -> u64 {
7515        unsafe { ffi::rocksdb_options_get_target_file_size_base(self.inner) }
7516    }
7517
7518    /// Returns the current `target_file_size_multiplier` setting.
7519    ///
7520    /// See [`Self::set_target_file_size_multiplier`] for what this controls.
7521    pub fn get_target_file_size_multiplier(&self) -> c_int {
7522        unsafe { ffi::rocksdb_options_get_target_file_size_multiplier(self.inner) }
7523    }
7524
7525    /// Returns the current `ttl` setting.
7526    ///
7527    /// See [`Self::set_ttl`] for what this controls.
7528    pub fn get_ttl(&self) -> u64 {
7529        unsafe { ffi::rocksdb_options_get_ttl(self.inner) }
7530    }
7531
7532    /// Returns the current `unordered_write` setting.
7533    ///
7534    /// See [`Self::set_unordered_write`] for what this controls.
7535    pub fn get_unordered_write(&self) -> bool {
7536        unsafe { ffi::rocksdb_options_get_unordered_write(self.inner) != 0 }
7537    }
7538
7539    /// Returns the current `use_adaptive_mutex` setting.
7540    ///
7541    /// See [`Self::set_use_adaptive_mutex`] for what this controls.
7542    pub fn get_use_adaptive_mutex(&self) -> bool {
7543        unsafe { ffi::rocksdb_options_get_use_adaptive_mutex(self.inner) != 0 }
7544    }
7545
7546    /// Returns the current `use_direct_io_for_flush_and_compaction` setting.
7547    ///
7548    /// See [`Self::set_use_direct_io_for_flush_and_compaction`] for what this controls.
7549    pub fn get_use_direct_io_for_flush_and_compaction(&self) -> bool {
7550        unsafe { ffi::rocksdb_options_get_use_direct_io_for_flush_and_compaction(self.inner) != 0 }
7551    }
7552
7553    /// Returns the current `use_direct_reads` setting.
7554    ///
7555    /// See [`Self::set_use_direct_reads`] for what this controls.
7556    pub fn get_use_direct_reads(&self) -> bool {
7557        unsafe { ffi::rocksdb_options_get_use_direct_reads(self.inner) != 0 }
7558    }
7559
7560    /// Returns the current `wal_bytes_per_sync` setting.
7561    ///
7562    /// See [`Self::set_wal_bytes_per_sync`] for what this controls.
7563    pub fn get_wal_bytes_per_sync(&self) -> u64 {
7564        unsafe { ffi::rocksdb_options_get_wal_bytes_per_sync(self.inner) }
7565    }
7566
7567    /// Returns the current `wal_size_limit_mb` setting.
7568    ///
7569    /// See [`Self::set_wal_size_limit_mb`] for what this controls.
7570    pub fn get_wal_size_limit_mb(&self) -> u64 {
7571        unsafe { ffi::rocksdb_options_get_WAL_size_limit_MB(self.inner) }
7572    }
7573
7574    /// Returns the current `wal_ttl_seconds` setting.
7575    ///
7576    /// See [`Self::set_wal_ttl_seconds`] for what this controls.
7577    pub fn get_wal_ttl_seconds(&self) -> u64 {
7578        unsafe { ffi::rocksdb_options_get_WAL_ttl_seconds(self.inner) }
7579    }
7580
7581    /// Returns the current `writable_file_max_buffer_size` setting.
7582    ///
7583    /// See [`Self::set_writable_file_max_buffer_size`] for what this controls.
7584    pub fn get_writable_file_max_buffer_size(&self) -> u64 {
7585        unsafe { ffi::rocksdb_options_get_writable_file_max_buffer_size(self.inner) }
7586    }
7587
7588    /// Returns the current `write_buffer_size` setting.
7589    ///
7590    /// See [`Self::set_write_buffer_size`] for what this controls.
7591    pub fn get_write_buffer_size(&self) -> usize {
7592        unsafe { ffi::rocksdb_options_get_write_buffer_size(self.inner) }
7593    }
7594
7595    /// Returns the current `write_identity_file` setting.
7596    ///
7597    /// See [`Self::set_write_identity_file`] for what this controls.
7598    pub fn get_write_identity_file(&self) -> bool {
7599        unsafe { ffi::rocksdb_options_get_write_identity_file(self.inner) != 0 }
7600    }
7601
7602    /// Enable blob files starting from a certain LSM tree level.
7603    ///
7604    /// For certain use cases that have a mix of short-lived and long-lived values, it might
7605    /// make sense to support extracting large values only during compactions whose output
7606    /// level is greater than or equal to a specified LSM tree level (e.g. compactions into
7607    /// L1/L2/... or above). This could reduce the space amplification caused by large values
7608    /// that are turned into garbage shortly after being written at the price of some write
7609    /// amplification incurred by long-lived values whose extraction to blob files is delayed.
7610    ///
7611    /// Default: 0
7612    ///
7613    /// Dynamically changeable through the SetOptions() API.
7614    pub fn set_blob_file_starting_level(&mut self, val: c_int) {
7615        unsafe {
7616            ffi::rocksdb_options_set_blob_file_starting_level(self.inner, val);
7617        }
7618    }
7619
7620    /// Bottommost-level counterpart of
7621    /// [`Self::set_compression_options_max_dict_buffer_bytes`].
7622    ///
7623    /// `enabled` must be true for the bottommost setting to take effect; otherwise
7624    /// the non-bottommost compression options apply.
7625    pub fn set_bottommost_compression_options_max_dict_buffer_bytes(
7626        &mut self,
7627        max_dict_buffer_bytes: u64,
7628        enabled: bool,
7629    ) {
7630        unsafe {
7631            ffi::rocksdb_options_set_bottommost_compression_options_max_dict_buffer_bytes(
7632                self.inner,
7633                max_dict_buffer_bytes,
7634                c_uchar::from(enabled),
7635            );
7636        }
7637    }
7638
7639    /// Bottommost-level counterpart of
7640    /// [`Self::set_compression_options_use_zstd_dict_trainer`].
7641    ///
7642    /// `enabled` must be true for the bottommost setting to take effect; otherwise
7643    /// the non-bottommost compression options apply.
7644    pub fn set_bottommost_compression_options_use_zstd_dict_trainer(
7645        &mut self,
7646        use_zstd_dict_trainer: bool,
7647        enabled: bool,
7648    ) {
7649        unsafe {
7650            ffi::rocksdb_options_set_bottommost_compression_options_use_zstd_dict_trainer(
7651                self.inner,
7652                c_uchar::from(use_zstd_dict_trainer),
7653                c_uchar::from(enabled),
7654            );
7655        }
7656    }
7657
7658    /// Limits the max buffered data used to build the compression dictionary.
7659    ///
7660    /// Limiting too strictly may harm dictionary effectiveness, because it forces
7661    /// RocksDB to pick samples from the start of the output SST, which may not
7662    /// represent the whole file. Setting it below `zstd_max_train_bytes` restricts
7663    /// how many samples reach the dictionary trainer, and setting it below
7664    /// `max_dict_bytes` restricts the size of the final dictionary.
7665    ///
7666    /// Default: `0`
7667    pub fn set_compression_options_max_dict_buffer_bytes(&mut self, val: u64) {
7668        unsafe {
7669            ffi::rocksdb_options_set_compression_options_max_dict_buffer_bytes(self.inner, val);
7670        }
7671    }
7672
7673    /// Selects how zstd dictionaries are generated.
7674    ///
7675    /// When true, buffered data is passed to zstd's dictionary trainer. When false,
7676    /// zstd's `ZDICT_finalizeDictionary()` is called instead, which saves CPU during
7677    /// training but usually gives a worse compression ratio.
7678    ///
7679    /// Default: `true`
7680    pub fn set_compression_options_use_zstd_dict_trainer(&mut self, val: bool) {
7681        unsafe {
7682            ffi::rocksdb_options_set_compression_options_use_zstd_dict_trainer(
7683                self.inner,
7684                c_uchar::from(val),
7685            );
7686        }
7687    }
7688
7689    /// Installs the built-in merge operator that adds 64-bit counters.
7690    ///
7691    /// Values are RocksDB fixed-width 64-bit integers, and a value that is not
7692    /// exactly that width is treated as 0 rather than failing the merge.
7693    pub fn set_uint64add_merge_operator(&mut self) {
7694        unsafe {
7695            ffi::rocksdb_options_set_uint64add_merge_operator(self.inner);
7696        }
7697    }
7698
7699    /// It is expected that the Identity file will be obsoleted by recording DB ID in the
7700    /// manifest (see write_dbid_to_manifest). Setting this to true maintains the historical
7701    /// behavior of writing an Identity file, while setting to false is expected to be the
7702    /// future default. This option might eventually be obsolete and removed as Identity files
7703    /// are phased out.
7704    pub fn set_write_identity_file(&mut self, val: bool) {
7705        unsafe {
7706            ffi::rocksdb_options_set_write_identity_file(self.inner, c_uchar::from(val));
7707        }
7708    }
7709}
7710
7711impl Default for Options {
7712    fn default() -> Self {
7713        unsafe {
7714            let opts = ffi::rocksdb_options_create();
7715            assert!(!opts.is_null(), "Could not create RocksDB options");
7716
7717            Self {
7718                inner: opts,
7719                outlive: OptionsMustOutliveDB::default(),
7720            }
7721        }
7722    }
7723}
7724
7725impl FlushOptions {
7726    pub fn new() -> FlushOptions {
7727        FlushOptions::default()
7728    }
7729
7730    /// Waits until the flush is done.
7731    ///
7732    /// Default: true
7733    ///
7734    /// # Examples
7735    ///
7736    /// ```
7737    /// use rust_rocksdb::FlushOptions;
7738    ///
7739    /// let mut options = FlushOptions::default();
7740    /// options.set_wait(false);
7741    /// ```
7742    pub fn set_wait(&mut self, wait: bool) {
7743        unsafe {
7744            ffi::rocksdb_flushoptions_set_wait(self.inner, c_uchar::from(wait));
7745        }
7746    }
7747
7748    /// If true, the flush would proceed immediately even it means writes will stall for the
7749    /// duration of the flush; if false the operation will wait until it's possible to do
7750    /// flush w/o causing stall or until required flush is performed by someone else
7751    /// (foreground call or background thread). Default: false
7752    pub fn set_allow_write_stall(&mut self, val: bool) {
7753        unsafe {
7754            ffi::rocksdb_flushoptions_set_allow_write_stall(self.inner, c_uchar::from(val));
7755        }
7756    }
7757
7758    /// Returns the value of the `allow_write_stall` option.
7759    pub fn get_allow_write_stall(&self) -> bool {
7760        unsafe { ffi::rocksdb_flushoptions_get_allow_write_stall(self.inner) != 0 }
7761    }
7762
7763    /// If true, use atomic flush to flush all column families atomically, regardless of the
7764    /// DBOptions::atomic_flush setting. When used with DB::Flush() or internally via
7765    /// GetLiveFilesStorageInfo(), this forces all column families to be flushed in a single
7766    /// atomic operation. Default: false (uses DBOptions::atomic_flush setting).
7767    pub fn set_force_atomic_flush(&mut self, val: bool) {
7768        unsafe {
7769            ffi::rocksdb_flushoptions_set_force_atomic_flush(self.inner, c_uchar::from(val));
7770        }
7771    }
7772
7773    /// Returns the value of the `force_atomic_flush` option.
7774    pub fn get_force_atomic_flush(&self) -> bool {
7775        unsafe { ffi::rocksdb_flushoptions_get_force_atomic_flush(self.inner) != 0 }
7776    }
7777
7778    /// If true (and `wait` is also true), Flush() will not return until the registered
7779    /// EventListener::OnFlushCompleted callbacks for the flushed memtables have finished
7780    /// running. By default (false), Flush(wait=true) may return as soon as the flush result
7781    /// is committed, which can be before (or while) the OnFlushCompleted callbacks execute on
7782    /// the background flush thread. Set this to true when the caller needs to observe the
7783    /// effects of its OnFlushCompleted listener(s) immediately after Flush() returns. Has no
7784    /// effect when `wait == false`. Default: false
7785    pub fn set_listener_wait(&mut self, val: bool) {
7786        unsafe {
7787            ffi::rocksdb_flushoptions_set_listener_wait(self.inner, c_uchar::from(val));
7788        }
7789    }
7790
7791    /// Returns the value of the `listener_wait` option.
7792    pub fn get_listener_wait(&self) -> bool {
7793        unsafe { ffi::rocksdb_flushoptions_get_listener_wait(self.inner) != 0 }
7794    }
7795
7796    /// Returns the current `wait` setting.
7797    ///
7798    /// See [`Self::set_wait`] for what this controls.
7799    pub fn get_wait(&self) -> bool {
7800        unsafe { ffi::rocksdb_flushoptions_get_wait(self.inner) != 0 }
7801    }
7802}
7803
7804impl Default for FlushOptions {
7805    fn default() -> Self {
7806        let flush_opts = unsafe { ffi::rocksdb_flushoptions_create() };
7807        assert!(
7808            !flush_opts.is_null(),
7809            "Could not create RocksDB flush options"
7810        );
7811
7812        Self { inner: flush_opts }
7813    }
7814}
7815
7816impl FlushWalOptions {
7817    #[must_use]
7818    pub fn new() -> FlushWalOptions {
7819        FlushWalOptions::default()
7820    }
7821
7822    pub(crate) fn as_ptr(&self) -> *const ffi::rocksdb_flushwaloptions_t {
7823        self.inner
7824    }
7825
7826    /// Calls `SyncWAL()` after the flush, so the writes are on durable storage
7827    /// rather than only handed to the operating system.
7828    ///
7829    /// Default: false
7830    pub fn set_sync(&mut self, sync: bool) {
7831        unsafe {
7832            ffi::rocksdb_flushwaloptions_set_sync(self.inner, c_uchar::from(sync));
7833        }
7834    }
7835
7836    /// Returns the value of the `sync` option.
7837    pub fn get_sync(&self) -> bool {
7838        unsafe { ffi::rocksdb_flushwaloptions_get_sync(self.inner) != 0 }
7839    }
7840
7841    /// Charges the IO this flush performs to the rate limiter set with
7842    /// [`Options::set_ratelimiter`] at the given priority, and passes the
7843    /// priority down to the file system.
7844    ///
7845    /// [`IoPriority::Total`] disables charging the rate limiter, which is the
7846    /// default.
7847    pub fn set_rate_limiter_priority(&mut self, priority: IoPriority) {
7848        unsafe {
7849            ffi::rocksdb_flushwaloptions_set_rate_limiter_priority(self.inner, priority as c_int);
7850        }
7851    }
7852
7853    /// Returns the value of the `rate_limiter_priority` option.
7854    ///
7855    /// Returns `None` if RocksDB reports a priority this crate has no variant
7856    /// for, which should not happen.
7857    pub fn get_rate_limiter_priority(&self) -> Option<IoPriority> {
7858        let raw = unsafe { ffi::rocksdb_flushwaloptions_get_rate_limiter_priority(self.inner) };
7859        IoPriority::try_from_raw(raw)
7860    }
7861}
7862
7863impl Default for FlushWalOptions {
7864    fn default() -> Self {
7865        let opts = unsafe { ffi::rocksdb_flushwaloptions_create() };
7866        assert!(
7867            !opts.is_null(),
7868            "Could not create RocksDB flush WAL options"
7869        );
7870
7871        Self { inner: opts }
7872    }
7873}
7874
7875impl SizeApproximationOptions {
7876    #[must_use]
7877    pub fn new() -> SizeApproximationOptions {
7878        SizeApproximationOptions::default()
7879    }
7880
7881    pub(crate) fn as_ptr(&self) -> *const ffi::rocksdb_size_approximation_options_t {
7882        self.inner
7883    }
7884
7885    /// Counts data still sitting in the memtables.
7886    ///
7887    /// Default: false
7888    pub fn set_include_memtables(&mut self, include: bool) {
7889        unsafe {
7890            ffi::rocksdb_size_approximation_options_set_include_memtables(
7891                self.inner,
7892                c_uchar::from(include),
7893            );
7894        }
7895    }
7896
7897    /// Returns the value of the `include_memtables` option.
7898    pub fn get_include_memtables(&self) -> bool {
7899        unsafe { ffi::rocksdb_size_approximation_options_get_include_memtables(self.inner) != 0 }
7900    }
7901
7902    /// Counts data written out to SST files.
7903    ///
7904    /// Default: true
7905    pub fn set_include_files(&mut self, include: bool) {
7906        unsafe {
7907            ffi::rocksdb_size_approximation_options_set_include_files(
7908                self.inner,
7909                c_uchar::from(include),
7910            );
7911        }
7912    }
7913
7914    /// Returns the value of the `include_files` option.
7915    pub fn get_include_files(&self) -> bool {
7916        unsafe { ffi::rocksdb_size_approximation_options_get_include_files(self.inner) != 0 }
7917    }
7918
7919    /// Counts a share of the blob files, prorated by how much of the SST data
7920    /// falls in the range:
7921    ///
7922    /// ```text
7923    /// blob_size_in_range ~= total_blob_size * (sst_in_range / total_sst)
7924    /// ```
7925    ///
7926    /// That assumes blob values are spread evenly across keys, so it skews when
7927    /// value sizes vary a lot. It also reports zero blob bytes when every key is
7928    /// still in a memtable, because there is no SST data to prorate against.
7929    ///
7930    /// Default: false
7931    pub fn set_include_blob_files(&mut self, include: bool) {
7932        unsafe {
7933            ffi::rocksdb_size_approximation_options_set_include_blob_files(
7934                self.inner,
7935                c_uchar::from(include),
7936            );
7937        }
7938    }
7939
7940    /// Returns the value of the `include_blob_files` option.
7941    pub fn get_include_blob_files(&self) -> bool {
7942        unsafe { ffi::rocksdb_size_approximation_options_get_include_blob_files(self.inner) != 0 }
7943    }
7944
7945    /// Lets the file-size estimate be off by up to
7946    /// `total_files_size * margin` in exchange for doing less work, so 0.1
7947    /// allows a 10% error.
7948    ///
7949    /// Zero or negative asks for the precise and more CPU intensive walk.
7950    pub fn set_files_size_error_margin(&mut self, margin: f64) {
7951        unsafe {
7952            ffi::rocksdb_size_approximation_options_set_files_size_error_margin(self.inner, margin);
7953        }
7954    }
7955
7956    /// Returns the value of the `files_size_error_margin` option.
7957    pub fn get_files_size_error_margin(&self) -> f64 {
7958        unsafe { ffi::rocksdb_size_approximation_options_get_files_size_error_margin(self.inner) }
7959    }
7960}
7961
7962impl Default for SizeApproximationOptions {
7963    fn default() -> Self {
7964        let opts = unsafe { ffi::rocksdb_size_approximation_options_create() };
7965        assert!(
7966            !opts.is_null(),
7967            "Could not create RocksDB size approximation options"
7968        );
7969
7970        Self { inner: opts }
7971    }
7972}
7973
7974impl WriteOptions {
7975    pub fn new() -> WriteOptions {
7976        WriteOptions::default()
7977    }
7978
7979    /// Sets the sync mode. If true, the write will be flushed
7980    /// from the operating system buffer cache before the write is considered complete.
7981    /// If this flag is true, writes will be slower.
7982    ///
7983    /// Default: false
7984    pub fn set_sync(&mut self, sync: bool) {
7985        unsafe {
7986            ffi::rocksdb_writeoptions_set_sync(self.inner, c_uchar::from(sync));
7987        }
7988    }
7989
7990    /// Sets whether WAL should be active or not.
7991    /// If true, writes will not first go to the write ahead log,
7992    /// and the write may got lost after a crash.
7993    ///
7994    /// Default: false
7995    pub fn disable_wal(&mut self, disable: bool) {
7996        unsafe {
7997            ffi::rocksdb_writeoptions_disable_WAL(self.inner, c_int::from(disable));
7998        }
7999    }
8000
8001    /// If true and if user is trying to write to column families that don't exist (they were dropped),
8002    /// ignore the write (don't return an error). If there are multiple writes in a WriteBatch,
8003    /// other writes will succeed.
8004    ///
8005    /// Default: false
8006    pub fn set_ignore_missing_column_families(&mut self, ignore: bool) {
8007        unsafe {
8008            ffi::rocksdb_writeoptions_set_ignore_missing_column_families(
8009                self.inner,
8010                c_uchar::from(ignore),
8011            );
8012        }
8013    }
8014
8015    /// If true and we need to wait or sleep for the write request, fails
8016    /// immediately with Status::Incomplete().
8017    ///
8018    /// Default: false
8019    pub fn set_no_slowdown(&mut self, no_slowdown: bool) {
8020        unsafe {
8021            ffi::rocksdb_writeoptions_set_no_slowdown(self.inner, c_uchar::from(no_slowdown));
8022        }
8023    }
8024
8025    /// If true, this write request is of lower priority if compaction is
8026    /// behind. In this case, no_slowdown = true, the request will be cancelled
8027    /// immediately with Status::Incomplete() returned. Otherwise, it will be
8028    /// slowed down. The slowdown value is determined by RocksDB to guarantee
8029    /// it introduces minimum impacts to high priority writes.
8030    ///
8031    /// Default: false
8032    pub fn set_low_pri(&mut self, v: bool) {
8033        unsafe {
8034            ffi::rocksdb_writeoptions_set_low_pri(self.inner, c_uchar::from(v));
8035        }
8036    }
8037
8038    /// If true, writebatch will maintain the last insert positions of each
8039    /// memtable as hints in concurrent write. It can improve write performance
8040    /// in concurrent writes if keys in one writebatch are sequential. In
8041    /// non-concurrent writes (when concurrent_memtable_writes is false) this
8042    /// option will be ignored.
8043    ///
8044    /// Default: false
8045    pub fn set_memtable_insert_hint_per_batch(&mut self, v: bool) {
8046        unsafe {
8047            ffi::rocksdb_writeoptions_set_memtable_insert_hint_per_batch(
8048                self.inner,
8049                c_uchar::from(v),
8050            );
8051        }
8052    }
8053
8054    /// EXPERIMENTAL
8055    pub fn set_io_activity(&mut self, val: c_int) {
8056        unsafe {
8057            ffi::rocksdb_writeoptions_set_io_activity(self.inner, val);
8058        }
8059    }
8060
8061    /// Returns the value of the `io_activity` option.
8062    pub fn get_io_activity(&self) -> c_int {
8063        unsafe { ffi::rocksdb_writeoptions_get_io_activity(self.inner) }
8064    }
8065
8066    /// `protection_bytes_per_key` is the number of bytes used to store protection information
8067    /// for each key entry. Currently supported values are zero (disabled) and eight.
8068    ///
8069    /// Default: zero (disabled).
8070    pub fn set_protection_bytes_per_key(&mut self, val: usize) {
8071        unsafe {
8072            ffi::rocksdb_writeoptions_set_protection_bytes_per_key(self.inner, val);
8073        }
8074    }
8075
8076    /// Returns the value of the `protection_bytes_per_key` option.
8077    pub fn get_protection_bytes_per_key(&self) -> usize {
8078        unsafe { ffi::rocksdb_writeoptions_get_protection_bytes_per_key(self.inner) }
8079    }
8080
8081    /// For file reads associated with this option, charge the internal rate limiter (see
8082    /// `DBOptions::rate_limiter`) at the specified priority. The special value
8083    /// `Env::IO_TOTAL` disables charging the rate limiter.
8084    ///
8085    /// The rate limiting is bypassed no matter this option's value for file reads on plain
8086    /// tables (these can exist when `ColumnFamilyOptions::table_factory` is a
8087    /// `PlainTableFactory`) and cuckoo tables (these can exist when
8088    /// `ColumnFamilyOptions::table_factory` is a `CuckooTableFactory`).
8089    ///
8090    /// The bytes charged to rate limiter may not exactly match the file read bytes since
8091    /// there are some seemingly insignificant reads, like for file headers/footers, that we
8092    /// currently do not charge to rate limiter.
8093    pub fn set_rate_limiter_priority(&mut self, val: c_int) {
8094        unsafe {
8095            ffi::rocksdb_writeoptions_set_rate_limiter_priority(self.inner, val);
8096        }
8097    }
8098
8099    /// Returns the value of the `rate_limiter_priority` option.
8100    pub fn get_rate_limiter_priority(&self) -> c_int {
8101        unsafe { ffi::rocksdb_writeoptions_get_rate_limiter_priority(self.inner) }
8102    }
8103
8104    /// Returns the current `disable_wal` setting.
8105    ///
8106    /// See [`Self::disable_wal`] for what this controls.
8107    pub fn get_disable_wal(&self) -> bool {
8108        unsafe { ffi::rocksdb_writeoptions_get_disable_WAL(self.inner) != 0 }
8109    }
8110
8111    /// Returns the current `ignore_missing_column_families` setting.
8112    ///
8113    /// See [`Self::set_ignore_missing_column_families`] for what this controls.
8114    pub fn get_ignore_missing_column_families(&self) -> bool {
8115        unsafe { ffi::rocksdb_writeoptions_get_ignore_missing_column_families(self.inner) != 0 }
8116    }
8117
8118    /// Returns the current `low_pri` setting.
8119    ///
8120    /// See [`Self::set_low_pri`] for what this controls.
8121    pub fn get_low_pri(&self) -> bool {
8122        unsafe { ffi::rocksdb_writeoptions_get_low_pri(self.inner) != 0 }
8123    }
8124
8125    /// Returns the current `memtable_insert_hint_per_batch` setting.
8126    ///
8127    /// See [`Self::set_memtable_insert_hint_per_batch`] for what this controls.
8128    pub fn get_memtable_insert_hint_per_batch(&self) -> bool {
8129        unsafe { ffi::rocksdb_writeoptions_get_memtable_insert_hint_per_batch(self.inner) != 0 }
8130    }
8131
8132    /// Returns the current `no_slowdown` setting.
8133    ///
8134    /// See [`Self::set_no_slowdown`] for what this controls.
8135    pub fn get_no_slowdown(&self) -> bool {
8136        unsafe { ffi::rocksdb_writeoptions_get_no_slowdown(self.inner) != 0 }
8137    }
8138
8139    /// Returns the current `sync` setting.
8140    ///
8141    /// See [`Self::set_sync`] for what this controls.
8142    pub fn get_sync(&self) -> bool {
8143        unsafe { ffi::rocksdb_writeoptions_get_sync(self.inner) != 0 }
8144    }
8145}
8146
8147impl Default for WriteOptions {
8148    fn default() -> Self {
8149        let write_opts = unsafe { ffi::rocksdb_writeoptions_create() };
8150        assert!(
8151            !write_opts.is_null(),
8152            "Could not create RocksDB write options"
8153        );
8154
8155        Self { inner: write_opts }
8156    }
8157}
8158
8159impl LruCacheOptions {
8160    /// Capacity of the cache, in the same units as the `charge` of each entry.
8161    /// This is typically measured in bytes, but can be a different unit if using
8162    /// kDontChargeCacheMetadata.
8163    pub fn set_capacity(&mut self, cap: usize) {
8164        unsafe {
8165            ffi::rocksdb_lru_cache_options_set_capacity(self.inner, cap);
8166        }
8167    }
8168
8169    /// Cache is sharded into 2^num_shard_bits shards, by hash of key.
8170    /// If < 0, a good default is chosen based on the capacity and the
8171    /// implementation. (Mutex-based implementations are much more reliant
8172    /// on many shards for parallel scalability.)
8173    pub fn set_num_shard_bits(&mut self, val: c_int) {
8174        unsafe {
8175            ffi::rocksdb_lru_cache_options_set_num_shard_bits(self.inner, val);
8176        }
8177    }
8178
8179    /// Allocates cache block memory through `allocator` instead of the system
8180    /// allocator.
8181    ///
8182    /// These options do not borrow the allocator. The C setter copies the
8183    /// `shared_ptr<MemoryAllocator>` out of the handle, so the allocator stays
8184    /// alive through the options and the caches built from them even after the
8185    /// [`MemoryAllocator`] here is dropped.
8186    pub fn set_memory_allocator(&mut self, allocator: &MemoryAllocator) {
8187        unsafe {
8188            ffi::rocksdb_lru_cache_options_set_memory_allocator(self.inner, allocator.as_ptr());
8189        }
8190    }
8191}
8192
8193impl Default for LruCacheOptions {
8194    fn default() -> Self {
8195        let inner = unsafe { ffi::rocksdb_lru_cache_options_create() };
8196        assert!(
8197            !inner.is_null(),
8198            "Could not create RocksDB LRU cache options"
8199        );
8200
8201        Self { inner }
8202    }
8203}
8204
8205#[derive(Debug, Copy, Clone, PartialEq, Eq)]
8206#[cfg_attr(feature = "serde1", derive(serde::Serialize, serde::Deserialize))]
8207#[repr(i32)]
8208pub enum ReadTier {
8209    /// Reads data in memtable, block cache, OS cache or storage.
8210    All = 0,
8211    /// Reads data in memtable or block cache.
8212    BlockCache,
8213    /// Reads persisted data. When WAL is disabled, this option will skip data in memtable.
8214    Persisted,
8215    /// Reads data in memtable. Used for memtable only iterators.
8216    Memtable,
8217}
8218
8219impl ReadTier {
8220    /// Decodes a raw `rocksdb::ReadTier`.
8221    ///
8222    /// This covers every tier RocksDB defines today, so `None` only means a future release
8223    /// added one.
8224    pub(crate) fn try_from_raw(raw: c_int) -> Option<Self> {
8225        match raw {
8226            n if n == ReadTier::All as c_int => Some(ReadTier::All),
8227            n if n == ReadTier::BlockCache as c_int => Some(ReadTier::BlockCache),
8228            n if n == ReadTier::Persisted as c_int => Some(ReadTier::Persisted),
8229            n if n == ReadTier::Memtable as c_int => Some(ReadTier::Memtable),
8230            _ => None,
8231        }
8232    }
8233}
8234
8235impl ReadOptions {
8236    // TODO add snapshot setting here
8237    // TODO add snapshot wrapper structs with proper destructors;
8238    // that struct needs an "iterator" impl too.
8239
8240    /// Specify whether the "data block"/"index block"/"filter block"
8241    /// read for this iteration should be cached in memory?
8242    /// Callers may wish to set this field to false for bulk scans.
8243    ///
8244    /// Default: true
8245    pub fn fill_cache(&mut self, v: bool) {
8246        unsafe {
8247            ffi::rocksdb_readoptions_set_fill_cache(self.inner, c_uchar::from(v));
8248        }
8249    }
8250
8251    /// Sets the snapshot which should be used for the read.
8252    /// The snapshot must belong to the DB that is being read and must
8253    /// not have been released.
8254    pub fn set_snapshot<D: DBAccess>(&mut self, snapshot: &SnapshotWithThreadMode<D>) {
8255        unsafe {
8256            ffi::rocksdb_readoptions_set_snapshot(self.inner, snapshot.inner);
8257        }
8258    }
8259
8260    /// Sets the lower bound for an iterator.
8261    pub fn set_iterate_lower_bound<K: Into<Vec<u8>>>(&mut self, key: K) {
8262        self.set_lower_bound_impl(Some(key.into()));
8263    }
8264
8265    /// Sets the upper bound for an iterator.
8266    /// The upper bound itself is not included on the iteration result.
8267    pub fn set_iterate_upper_bound<K: Into<Vec<u8>>>(&mut self, key: K) {
8268        self.set_upper_bound_impl(Some(key.into()));
8269    }
8270
8271    /// Sets lower and upper bounds based on the provided range.  This is
8272    /// similar to setting lower and upper bounds separately except that it also
8273    /// allows either bound to be reset.
8274    ///
8275    /// The argument can be a regular Rust range, e.g. `lower..upper`.  However,
8276    /// since RocksDB upper bound is always excluded (i.e. range can never be
8277    /// fully closed) inclusive ranges (`lower..=upper` and `..=upper`) are not
8278    /// supported.  For example:
8279    ///
8280    /// ```
8281    /// let mut options = rust_rocksdb::ReadOptions::default();
8282    /// options.set_iterate_range("xy".as_bytes().."xz".as_bytes());
8283    /// ```
8284    ///
8285    /// In addition, [`crate::PrefixRange`] can be used to specify a range of
8286    /// keys with a given prefix.  In particular, the above example is
8287    /// equivalent to:
8288    ///
8289    /// ```
8290    /// let mut options = rust_rocksdb::ReadOptions::default();
8291    /// options.set_iterate_range(rust_rocksdb::PrefixRange("xy".as_bytes()));
8292    /// ```
8293    ///
8294    /// Note that setting range using this method is separate to using prefix
8295    /// iterators.  Prefix iterators use prefix extractor configured for
8296    /// a column family.  Setting bounds via [`crate::PrefixRange`] is more akin
8297    /// to using manual prefix.
8298    ///
8299    /// Using this method clears any previously set bounds.  In other words, the
8300    /// bounds can be reset by setting the range to `..` as in:
8301    ///
8302    /// ```
8303    /// let mut options = rust_rocksdb::ReadOptions::default();
8304    /// options.set_iterate_range(..);
8305    /// ```
8306    pub fn set_iterate_range(&mut self, range: impl crate::IterateBounds) {
8307        let (lower, upper) = range.into_bounds();
8308        self.set_lower_bound_impl(lower);
8309        self.set_upper_bound_impl(upper);
8310    }
8311
8312    /// Equivalent to `set_iterate_range(PrefixRange(prefix))`, but writes into
8313    /// the already-allocated bound buffers instead of building two fresh
8314    /// `Vec<u8>`s and dropping the old ones.
8315    ///
8316    /// `set_iterate_range` has to allocate because `IterateBounds::into_bounds`
8317    /// hands back owned `Vec`s. That is fine for one-off configuration, but the
8318    /// hot prefix-probe path reuses a cached `ReadOptions` specifically to avoid
8319    /// per-call allocation, and then threw that away by reallocating both bounds
8320    /// on every call. Reusing the buffers makes the steady state allocation-free.
8321    pub(crate) fn set_prefix_range_in_place(&mut self, prefix: &[u8]) {
8322        // An empty prefix covers the full keyspace, i.e. no bounds at all.
8323        if prefix.is_empty() {
8324            self.set_lower_bound_impl(None);
8325            self.set_upper_bound_impl(None);
8326            return;
8327        }
8328
8329        // Lower bound is the prefix itself. The buffer can be reallocated by
8330        // `extend_from_slice`, so the pointer has to be handed to RocksDB again
8331        // even when the bound was already set.
8332        let (ptr, len) = {
8333            let lower = self.iterate_lower_bound.get_or_insert_with(Vec::new);
8334            lower.clear();
8335            lower.extend_from_slice(prefix);
8336            (lower.as_ptr() as *const c_char, lower.len())
8337        };
8338        unsafe {
8339            ffi::rocksdb_readoptions_set_iterate_lower_bound(self.inner, ptr, len);
8340        }
8341
8342        // Upper bound is the successor of the prefix: strip trailing 0xff bytes,
8343        // then increment the last remaining one. A prefix that is entirely 0xff
8344        // has no successor, so it is an unbounded scan. This mirrors
8345        // `iter_range::next_prefix`.
8346        let ffs = prefix
8347            .iter()
8348            .rev()
8349            .take_while(|&&byte| byte == u8::MAX)
8350            .count();
8351        let head = &prefix[..prefix.len() - ffs];
8352        if head.is_empty() {
8353            self.set_upper_bound_impl(None);
8354            return;
8355        }
8356        let (ptr, len) = {
8357            let upper = self.iterate_upper_bound.get_or_insert_with(Vec::new);
8358            upper.clear();
8359            upper.extend_from_slice(head);
8360            // `head` is non-empty and its last byte is not 0xff, so this cannot
8361            // overflow.
8362            *upper.last_mut().unwrap() += 1;
8363            (upper.as_ptr() as *const c_char, upper.len())
8364        };
8365        unsafe {
8366            ffi::rocksdb_readoptions_set_iterate_upper_bound(self.inner, ptr, len);
8367        }
8368    }
8369
8370    fn set_lower_bound_impl(&mut self, bound: Option<Vec<u8>>) {
8371        let (ptr, len) = if let Some(ref bound) = bound {
8372            (bound.as_ptr() as *const c_char, bound.len())
8373        } else if self.iterate_lower_bound.is_some() {
8374            (std::ptr::null(), 0)
8375        } else {
8376            return;
8377        };
8378        self.iterate_lower_bound = bound;
8379        unsafe {
8380            ffi::rocksdb_readoptions_set_iterate_lower_bound(self.inner, ptr, len);
8381        }
8382    }
8383
8384    fn set_upper_bound_impl(&mut self, bound: Option<Vec<u8>>) {
8385        let (ptr, len) = if let Some(ref bound) = bound {
8386            (bound.as_ptr() as *const c_char, bound.len())
8387        } else if self.iterate_upper_bound.is_some() {
8388            (std::ptr::null(), 0)
8389        } else {
8390            return;
8391        };
8392        self.iterate_upper_bound = bound;
8393        unsafe {
8394            ffi::rocksdb_readoptions_set_iterate_upper_bound(self.inner, ptr, len);
8395        }
8396    }
8397
8398    /// Specify if this read request should process data that ALREADY
8399    /// resides on a particular cache. If the required data is not
8400    /// found at the specified cache, then Status::Incomplete is returned.
8401    ///
8402    /// Default: ::All
8403    pub fn set_read_tier(&mut self, tier: ReadTier) {
8404        unsafe {
8405            ffi::rocksdb_readoptions_set_read_tier(self.inner, tier as c_int);
8406        }
8407    }
8408
8409    /// The tier set by [`Self::set_read_tier`].
8410    ///
8411    /// [`ReadTier`] covers every tier RocksDB defines today, so `None` only shows up if a
8412    /// future release adds one.
8413    pub fn get_read_tier(&self) -> Option<ReadTier> {
8414        let raw = unsafe { ffi::rocksdb_readoptions_get_read_tier(self.inner) };
8415        ReadTier::try_from_raw(raw)
8416    }
8417
8418    /// Enforce that the iterator only iterates over the same
8419    /// prefix as the seek.
8420    /// This option is effective only for prefix seeks, i.e. prefix_extractor is
8421    /// non-null for the column family and total_order_seek is false.  Unlike
8422    /// iterate_upper_bound, prefix_same_as_start only works within a prefix
8423    /// but in both directions.
8424    ///
8425    /// Default: false
8426    pub fn set_prefix_same_as_start(&mut self, v: bool) {
8427        unsafe {
8428            ffi::rocksdb_readoptions_set_prefix_same_as_start(self.inner, c_uchar::from(v));
8429        }
8430    }
8431
8432    /// Enable a total order seek regardless of index format (e.g. hash index)
8433    /// used in the table. Some table format (e.g. plain table) may not support
8434    /// this option.
8435    ///
8436    /// If true when calling Get(), we also skip prefix bloom when reading from
8437    /// block based table. It provides a way to read existing data after
8438    /// changing implementation of prefix extractor.
8439    pub fn set_total_order_seek(&mut self, v: bool) {
8440        unsafe {
8441            ffi::rocksdb_readoptions_set_total_order_seek(self.inner, c_uchar::from(v));
8442        }
8443    }
8444
8445    /// Sets a threshold for the number of keys that can be skipped
8446    /// before failing an iterator seek as incomplete. The default value of 0 should be used to
8447    /// never fail a request as incomplete, even on skipping too many keys.
8448    ///
8449    /// Default: 0
8450    pub fn set_max_skippable_internal_keys(&mut self, num: u64) {
8451        unsafe {
8452            ffi::rocksdb_readoptions_set_max_skippable_internal_keys(self.inner, num);
8453        }
8454    }
8455
8456    /// If true, when PurgeObsoleteFile is called in CleanupIteratorState, we schedule a background job
8457    /// in the flush job queue and delete obsolete files in background.
8458    ///
8459    /// Default: false
8460    pub fn set_background_purge_on_iterator_cleanup(&mut self, v: bool) {
8461        unsafe {
8462            ffi::rocksdb_readoptions_set_background_purge_on_iterator_cleanup(
8463                self.inner,
8464                c_uchar::from(v),
8465            );
8466        }
8467    }
8468
8469    /// If true, keys deleted using the DeleteRange() API will be visible to
8470    /// readers until they are naturally deleted during compaction.
8471    ///
8472    /// Default: false
8473    #[deprecated(
8474        note = "deprecated in RocksDB 10.2.1: no performance impact if DeleteRange is not used"
8475    )]
8476    pub fn set_ignore_range_deletions(&mut self, v: bool) {
8477        unsafe {
8478            ffi::rocksdb_readoptions_set_ignore_range_deletions(self.inner, c_uchar::from(v));
8479        }
8480    }
8481
8482    /// Returns the value of the `ignore_range_deletions` option.
8483    ///
8484    /// Deprecated in RocksDB 10.2.1 along with its setter: there is no performance impact if
8485    /// `DeleteRange` is not used.
8486    pub fn get_ignore_range_deletions(&self) -> bool {
8487        unsafe { ffi::rocksdb_readoptions_get_ignore_range_deletions(self.inner) != 0 }
8488    }
8489
8490    /// If true, all data read from underlying storage will be
8491    /// verified against corresponding checksums.
8492    ///
8493    /// Default: true
8494    pub fn set_verify_checksums(&mut self, v: bool) {
8495        unsafe {
8496            ffi::rocksdb_readoptions_set_verify_checksums(self.inner, c_uchar::from(v));
8497        }
8498    }
8499
8500    /// If non-zero, an iterator will create a new table reader which
8501    /// performs reads of the given size. Using a large size (> 2MB) can
8502    /// improve the performance of forward iteration on spinning disks.
8503    /// Default: 0
8504    ///
8505    /// ```
8506    /// use rust_rocksdb::{ReadOptions};
8507    ///
8508    /// let mut opts = ReadOptions::default();
8509    /// opts.set_readahead_size(4_194_304); // 4mb
8510    /// ```
8511    pub fn set_readahead_size(&mut self, v: usize) {
8512        unsafe {
8513            ffi::rocksdb_readoptions_set_readahead_size(self.inner, v as size_t);
8514        }
8515    }
8516
8517    /// If auto_readahead_size is set to true, it will auto tune the readahead_size
8518    /// during scans internally.
8519    /// For this feature to be enabled, iterate_upper_bound must also be specified.
8520    ///
8521    /// NOTE: - Recommended for forward Scans only.
8522    ///       - If there is a backward scans, this option will be
8523    ///         disabled internally and won't be enabled again if the forward scan
8524    ///         is issued again.
8525    ///
8526    /// Default: true
8527    pub fn set_auto_readahead_size(&mut self, v: bool) {
8528        unsafe {
8529            ffi::rocksdb_readoptions_set_auto_readahead_size(self.inner, c_uchar::from(v));
8530        }
8531    }
8532
8533    /// If true, create a tailing iterator. Note that tailing iterators
8534    /// only support moving in the forward direction. Iterating in reverse
8535    /// or seek_to_last are not supported.
8536    pub fn set_tailing(&mut self, v: bool) {
8537        unsafe {
8538            ffi::rocksdb_readoptions_set_tailing(self.inner, c_uchar::from(v));
8539        }
8540    }
8541
8542    /// Specifies the value of "pin_data". If true, it keeps the blocks
8543    /// loaded by the iterator pinned in memory as long as the iterator is not deleted,
8544    /// If used when reading from tables created with
8545    /// BlockBasedTableOptions::use_delta_encoding = false,
8546    /// Iterator's property "rocksdb.iterator.is-key-pinned" is guaranteed to
8547    /// return 1.
8548    ///
8549    /// Default: false
8550    pub fn set_pin_data(&mut self, v: bool) {
8551        unsafe {
8552            ffi::rocksdb_readoptions_set_pin_data(self.inner, c_uchar::from(v));
8553        }
8554    }
8555
8556    /// Asynchronously prefetch some data.
8557    ///
8558    /// Used for sequential reads and internal automatic prefetching.
8559    ///
8560    /// Default: `false`
8561    pub fn set_async_io(&mut self, v: bool) {
8562        unsafe {
8563            ffi::rocksdb_readoptions_set_async_io(self.inner, c_uchar::from(v));
8564        }
8565    }
8566
8567    /// Selects the multi-level vs single-level parallel `MultiGet` path when
8568    /// the library is built with `USE_COROUTINES` (the `coroutines` cargo
8569    /// feature) and `set_async_io(true)` has been called.
8570    ///
8571    /// When `true` (the C++ default), `MultiGet` parallelises reads across
8572    /// LSM levels, giving the lowest latency at the cost of higher CPU and
8573    /// coroutine scheduling overhead. When `false`, parallelism is limited
8574    /// to within a single level, trading some latency for CPU savings.
8575    ///
8576    /// Has no effect outside of `USE_COROUTINES` builds with `async_io=true`.
8577    /// With either condition unmet, both code paths in `db/version_set.cc`
8578    /// fall through to the synchronous per-file lookup regardless of this
8579    /// flag's value.
8580    ///
8581    /// See the RocksDB ["Asynchronous IO in RocksDB" blog
8582    /// post](https://rocksdb.org/blog/2022/10/07/asynchronous-io-in-rocksdb.html)
8583    /// for the qualitative tradeoff: `optimize_multiget_for_io=true`
8584    /// (multi-level) is the lowest-latency configuration but costs the most
8585    /// CPU; `optimize_multiget_for_io=false` (single-level, with `async_io`
8586    /// still on) retains most of the latency win at meaningfully lower CPU.
8587    ///
8588    /// Default: `true`
8589    pub fn set_optimize_multiget_for_io(&mut self, v: bool) {
8590        unsafe {
8591            ffi::rocksdb_readoptions_set_optimize_multiget_for_io(self.inner, c_uchar::from(v));
8592        }
8593    }
8594
8595    /// Returns the current value of [`Self::set_optimize_multiget_for_io`].
8596    ///
8597    /// Provided primarily for tests that want to confirm the setter is wired
8598    /// through to the underlying C++ `ReadOptions`. Reads through to the C
8599    /// API getter without exposing the underlying `c_uchar` representation.
8600    pub fn get_optimize_multiget_for_io(&self) -> bool {
8601        unsafe { ffi::rocksdb_readoptions_get_optimize_multiget_for_io(self.inner) != 0 }
8602    }
8603
8604    /// Deadline for completing an API call (Get/MultiGet/Seek/Next for now)
8605    /// in microseconds.
8606    /// It should be set to microseconds since epoch, i.e, gettimeofday or
8607    /// equivalent plus allowed duration in microseconds.
8608    /// This is best effort. The call may exceed the deadline if there is IO
8609    /// involved and the file system doesn't support deadlines, or due to
8610    /// checking for deadline periodically rather than for every key if
8611    /// processing a batch
8612    pub fn set_deadline(&mut self, microseconds: u64) {
8613        unsafe {
8614            ffi::rocksdb_readoptions_set_deadline(self.inner, microseconds);
8615        }
8616    }
8617
8618    /// A timeout in microseconds to be passed to the underlying FileSystem for
8619    /// reads. As opposed to deadline, this determines the timeout for each
8620    /// individual file read request. If a MultiGet/Get/Seek/Next etc call
8621    /// results in multiple reads, each read can last up to io_timeout us.
8622    pub fn set_io_timeout(&mut self, microseconds: u64) {
8623        unsafe {
8624            ffi::rocksdb_readoptions_set_io_timeout(self.inner, microseconds);
8625        }
8626    }
8627
8628    /// Timestamp of operation. Read should return the latest data visible to the
8629    /// specified timestamp. All timestamps of the same database must be of the
8630    /// same length and format. The user is responsible for providing a customized
8631    /// compare function via Comparator to order <key, timestamp> tuples.
8632    /// For iterator, iter_start_ts is the lower bound (older) and timestamp
8633    /// serves as the upper bound. Versions of the same record that fall in
8634    /// the timestamp range will be returned. If iter_start_ts is nullptr,
8635    /// only the most recent version visible to timestamp is returned.
8636    /// The user-specified timestamp feature is still under active development,
8637    /// and the API is subject to change.
8638    pub fn set_timestamp<S: Into<Vec<u8>>>(&mut self, ts: S) {
8639        self.set_timestamp_impl(Some(ts.into()));
8640    }
8641
8642    fn set_timestamp_impl(&mut self, ts: Option<Vec<u8>>) {
8643        let (ptr, len) = if let Some(ref ts) = ts {
8644            (ts.as_ptr() as *const c_char, ts.len())
8645        } else if self.timestamp.is_some() {
8646            // The stored timestamp is a `Some` but we're updating it to a `None`.
8647            // This means to cancel a previously set timestamp.
8648            // To do this, use a null pointer and zero length.
8649            (std::ptr::null(), 0)
8650        } else {
8651            return;
8652        };
8653        self.timestamp = ts;
8654        unsafe {
8655            ffi::rocksdb_readoptions_set_timestamp(self.inner, ptr, len);
8656        }
8657    }
8658
8659    /// See `set_timestamp`
8660    pub fn set_iter_start_ts<S: Into<Vec<u8>>>(&mut self, ts: S) {
8661        self.set_iter_start_ts_impl(Some(ts.into()));
8662    }
8663
8664    fn set_iter_start_ts_impl(&mut self, ts: Option<Vec<u8>>) {
8665        let (ptr, len) = if let Some(ref ts) = ts {
8666            (ts.as_ptr() as *const c_char, ts.len())
8667        } else if self.timestamp.is_some() {
8668            (std::ptr::null(), 0)
8669        } else {
8670            return;
8671        };
8672        self.iter_start_ts = ts;
8673        unsafe {
8674            ffi::rocksdb_readoptions_set_iter_start_ts(self.inner, ptr, len);
8675        }
8676    }
8677
8678    /// For iterators, RocksDB does auto-readahead on noticing more than two sequential reads
8679    /// for a table file if user doesn't provide readahead_size. The readahead starts at 8KB
8680    /// and doubles on every additional read upto max_auto_readahead_size only when reads are
8681    /// sequential. However at each level, if iterator moves over next file, readahead_size
8682    /// starts again from 8KB.
8683    ///
8684    /// By enabling this option, RocksDB will do some enhancements for prefetching the data.
8685    pub fn set_adaptive_readahead(&mut self, val: bool) {
8686        unsafe {
8687            ffi::rocksdb_readoptions_set_adaptive_readahead(self.inner, c_uchar::from(val));
8688        }
8689    }
8690
8691    /// Returns the value of the `adaptive_readahead` option.
8692    pub fn get_adaptive_readahead(&self) -> bool {
8693        unsafe { ffi::rocksdb_readoptions_get_adaptive_readahead(self.inner) != 0 }
8694    }
8695
8696    /// When set, the iterator may defer loading and/or preparing the value when moving to a
8697    /// different entry (i.e. during SeekToFirst/SeekToLast/Seek/ SeekForPrev/Next/Prev
8698    /// operations). This can be used to save on I/O and/or CPU when the values associated
8699    /// with certain keys may not be used by the application. See also
8700    /// IteratorBase::PrepareValue().
8701    ///
8702    /// Note: this option currently only applies to 1) large values stored in blob files using
8703    /// BlobDB and 2) multi-column-family iterators (CoalescingIterator and
8704    /// AttributeGroupIterator). Otherwise, it has no effect.
8705    ///
8706    /// Default: false
8707    pub fn set_allow_unprepared_value(&mut self, val: bool) {
8708        unsafe {
8709            ffi::rocksdb_readoptions_set_allow_unprepared_value(self.inner, c_uchar::from(val));
8710        }
8711    }
8712
8713    /// Returns the value of the `allow_unprepared_value` option.
8714    pub fn get_allow_unprepared_value(&self) -> bool {
8715        unsafe { ffi::rocksdb_readoptions_get_allow_unprepared_value(self.inner) != 0 }
8716    }
8717
8718    /// When true, by default use total_order_seek = true, and RocksDB can selectively enable
8719    /// prefix seek mode if won't generate a different result from total_order_seek, based on
8720    /// seek key, and iterator upper bound. BUG: Using
8721    /// Comparator::IsSameLengthImmediateSuccessor and SliceTransform::FullLengthEnabled to
8722    /// enable prefix mode in cases where prefix of upper bound differs from prefix of seek
8723    /// key has a flaw. If present in the DB, "short keys" (shorter than "full length" prefix)
8724    /// can be omitted from auto_prefix_mode iteration when they would be present in
8725    /// total_order_seek iteration, regardless of whether the short keys are "in domain" of
8726    /// the prefix extractor. This is not an issue if no short keys are added to DB or are not
8727    /// expected to be returned by such iterators. (We are also assuming the new condition on
8728    /// IsSameLengthImmediateSuccessor is satisfied; see its BUG section). A bug example is in
8729    /// DBTest2::AutoPrefixMode1, search for "BUG".
8730    pub fn set_auto_prefix_mode(&mut self, val: bool) {
8731        unsafe {
8732            ffi::rocksdb_readoptions_set_auto_prefix_mode(self.inner, c_uchar::from(val));
8733        }
8734    }
8735
8736    /// Returns the value of the `auto_prefix_mode` option.
8737    pub fn get_auto_prefix_mode(&self) -> bool {
8738        unsafe { ffi::rocksdb_readoptions_get_auto_prefix_mode(self.inner) != 0 }
8739    }
8740
8741    /// If auto_readahead_size is set to true, it will auto tune the readahead_size during
8742    /// scans internally based on block cache data when block cache is enabled, iteration
8743    /// upper bound when `iterate_upper_bound != nullptr` and prefix when
8744    /// `prefix_same_as_start == true`
8745    ///
8746    /// Besides enabling block cache, it also requires `iterate_upper_bound != nullptr` or
8747    /// `prefix_same_as_start == true` for this option to take effect
8748    ///
8749    /// To be specific, it does the following: (1) When `iterate_upper_bound` is specified,
8750    /// trim the readahead so the readahead does not exceed iteration upper bound (2) When
8751    /// `prefix_same_as_start` is set to true, trim the readahead so data blocks containing
8752    /// keys that are not in the same prefix as the seek key in `Seek()` are not prefetched
8753    /// - Limition: `Seek(key)` instead of `SeekToFirst()` needs to be called in order for
8754    ///   this trimming to take effect
8755    ///
8756    /// NOTE: - Used for forward Scans only.
8757    /// - If there is a backward scans, this option will be disabled internally and won't be
8758    ///   enabled again if the forward scan is issued again.
8759    ///
8760    /// Default: true
8761    pub fn get_auto_readahead_size(&self) -> bool {
8762        unsafe { ffi::rocksdb_readoptions_get_auto_readahead_size(self.inner) != 0 }
8763    }
8764
8765    /// EXPERIMENTAL
8766    ///
8767    /// Long-running iterators are holding onto memory and storage resources long after they
8768    /// are obsolete. This setting (when enabled) will fix that problem for as long as
8769    /// iterator periodically makes some progress and its supplied `read_options` was
8770    /// configured with non-nullptr `snapshot` value. The feature is engineered so that the
8771    /// performance impact should be negligible. We expect the default value to be true some
8772    /// time in the future.
8773    ///
8774    /// NOTE 1: Does not have effect on TransactionDB with WRITE_PREPARED or WRITE_UNPREPARED
8775    /// policies (currently incompatible).
8776    ///
8777    /// NOTE 2: True is not recommended if using user-defined timestamp with
8778    /// persist_user_defined_timestamps=false and non-nullptr ReadOptions::timestamp or
8779    /// ReadOptions::iter_start_ts, because auto-refreshing iterator will not prevent user
8780    /// timestamp information from being dropped during iteration. Auto-refresh might be
8781    /// disabled for this combination in the future.
8782    ///
8783    /// Default: false
8784    pub fn set_auto_refresh_iterator_with_snapshot(&mut self, val: bool) {
8785        unsafe {
8786            ffi::rocksdb_readoptions_set_auto_refresh_iterator_with_snapshot(
8787                self.inner,
8788                c_uchar::from(val),
8789            );
8790        }
8791    }
8792
8793    /// Returns the value of the `auto_refresh_iterator_with_snapshot` option.
8794    pub fn get_auto_refresh_iterator_with_snapshot(&self) -> bool {
8795        unsafe { ffi::rocksdb_readoptions_get_auto_refresh_iterator_with_snapshot(self.inner) != 0 }
8796    }
8797
8798    /// EXPERIMENTAL
8799    pub fn set_io_activity(&mut self, val: c_int) {
8800        unsafe {
8801            ffi::rocksdb_readoptions_set_io_activity(self.inner, val);
8802        }
8803    }
8804
8805    /// Returns the value of the `io_activity` option.
8806    pub fn get_io_activity(&self) -> c_int {
8807        unsafe { ffi::rocksdb_readoptions_get_io_activity(self.inner) }
8808    }
8809
8810    /// When the number of merge operands applied exceeds this threshold during a successful
8811    /// query, the operation will return a special OK Status with subcode
8812    /// kMergeOperandThresholdExceeded. Currently only applies to point lookups and is
8813    /// disabled by default.
8814    pub fn set_merge_operand_count_threshold(&mut self, val: usize) {
8815        unsafe {
8816            ffi::rocksdb_readoptions_set_merge_operand_count_threshold(self.inner, val);
8817        }
8818    }
8819
8820    /// Returns the value of the `merge_operand_count_threshold` option.
8821    pub fn get_merge_operand_count_threshold(&self) -> usize {
8822        unsafe { ffi::rocksdb_readoptions_get_merge_operand_count_threshold(self.inner) }
8823    }
8824
8825    /// For file reads associated with this option, charge the internal rate limiter (see
8826    /// `DBOptions::rate_limiter`) at the specified priority. The special value
8827    /// `Env::IO_TOTAL` disables charging the rate limiter.
8828    ///
8829    /// The rate limiting is bypassed no matter this option's value for file reads on plain
8830    /// tables (these can exist when `ColumnFamilyOptions::table_factory` is a
8831    /// `PlainTableFactory`) and cuckoo tables (these can exist when
8832    /// `ColumnFamilyOptions::table_factory` is a `CuckooTableFactory`).
8833    ///
8834    /// The bytes charged to rate limiter may not exactly match the file read bytes since
8835    /// there are some seemingly insignificant reads, like for file headers/footers, that we
8836    /// currently do not charge to rate limiter.
8837    pub fn set_rate_limiter_priority(&mut self, val: c_int) {
8838        unsafe {
8839            ffi::rocksdb_readoptions_set_rate_limiter_priority(self.inner, val);
8840        }
8841    }
8842
8843    /// Returns the value of the `rate_limiter_priority` option.
8844    pub fn get_rate_limiter_priority(&self) -> c_int {
8845        unsafe { ffi::rocksdb_readoptions_get_rate_limiter_priority(self.inner) }
8846    }
8847
8848    /// Tags this read with an application chosen id, so filesystem metrics and logs can be
8849    /// lined up with RocksDB and application logs for the same request.
8850    ///
8851    /// The id does not have to be unique per RocksDB call. It usually names an application
8852    /// level request that fans out into several of them.
8853    ///
8854    /// The `ReadOptions` owns a copy, so `id` does not have to outlive this call. Passing an
8855    /// empty string sets an empty id rather than removing it, use
8856    /// [`Self::clear_request_id`] for that.
8857    pub fn set_request_id(&mut self, id: impl AsRef<str>) {
8858        let id = id.as_ref();
8859        unsafe {
8860            ffi::rocksdb_readoptions_set_request_id(
8861                self.inner,
8862                id.as_ptr().cast::<c_char>(),
8863                id.len(),
8864            );
8865        }
8866    }
8867
8868    /// The id set by [`Self::set_request_id`], or `None` when there is none.
8869    pub fn get_request_id(&self) -> Option<String> {
8870        // Borrowed: `c.cc` hands back a pointer into the `std::string` the read options own,
8871        // and null when no id is set. Copy it, do not free it.
8872        let mut len: size_t = 0;
8873        let id = unsafe { ffi::rocksdb_readoptions_get_request_id(self.inner, &raw mut len) };
8874        if id.is_null() {
8875            return None;
8876        }
8877        Some(unsafe { borrowed_string(id, len) })
8878    }
8879
8880    /// Drops the request id, so this read is untagged again.
8881    ///
8882    /// See [`Self::set_request_id`].
8883    pub fn clear_request_id(&mut self) {
8884        unsafe {
8885            ffi::rocksdb_readoptions_clear_request_id(self.inner);
8886        }
8887    }
8888
8889    /// Skips whole SST files during iteration based on their properties.
8890    ///
8891    /// `filter` runs once per table an iterator is about to open. Returning `false` skips the
8892    /// file, returning `true` scans it. This only affects iterators, point lookups ignore it.
8893    ///
8894    /// Creating an iterator on a read-write DB fails with `InvalidArgument` when the target
8895    /// column family has a non-zero `min_tombstones_for_range_conversion`, because skipping a
8896    /// file that holds tombstones could make deletes reappear. Turning that option off does
8897    /// not undo range tombstones RocksDB has already written, so account for the ones already
8898    /// in the memtable and SST files before relying on a filter.
8899    ///
8900    /// `filter` must be `Send + Sync` because RocksDB calls it from whichever thread drives
8901    /// the iterator. It replaces any filter set earlier. A panic inside it crosses a C frame,
8902    /// which aborts the process.
8903    pub fn set_table_filter<F>(&mut self, filter: F)
8904    where
8905        F: Fn(&TableProperties<'_>) -> bool + Send + Sync + 'static,
8906    {
8907        // Ownership, from `rocksdb_readoptions_t` in `db/c.cc`:
8908        //
8909        //  * `SetTableFilter` calls `ClearTableFilter` first, so setting a second filter runs
8910        //    the first one's destructor. Calling this twice does not leak.
8911        //  * `ClearTableFilter` nulls the destructor pointer after calling it, so
8912        //    `clear_table_filter` is idempotent.
8913        //  * `~rocksdb_readoptions_t` calls `ClearTableFilter` too, so dropping the
8914        //    `ReadOptions` reclaims the box.
8915        //
8916        // Together that is exactly one drop on every path. The C++ lambda installed into
8917        // `rep.table_filter` captures the state pointer raw, but `ClearTableFilter` resets
8918        // `rep.table_filter` before freeing the state, so the lambda can never outlive it
8919        // here. RocksDB copies `ReadOptions` by value when an iterator is created, and that
8920        // copy keeps the raw pointer, which is safe because an iterator takes ownership of
8921        // the whole `ReadOptions` and nothing can call these methods on it again.
8922        let filter: TableFilterCallback = Box::new(filter);
8923        let state = Box::into_raw(Box::new(filter));
8924        unsafe {
8925            ffi::rocksdb_readoptions_set_table_filter(
8926                self.inner,
8927                state.cast::<c_void>(),
8928                Some(table_filter_destructor),
8929                Some(table_filter_callback),
8930            );
8931        }
8932    }
8933
8934    /// Drops the table filter, so iteration scans every file again.
8935    ///
8936    /// See [`Self::set_table_filter`].
8937    pub fn clear_table_filter(&mut self) {
8938        unsafe {
8939            ffi::rocksdb_readoptions_clear_table_filter(self.inner);
8940        }
8941    }
8942
8943    /// Whether a table filter is installed.
8944    ///
8945    /// See [`Self::set_table_filter`].
8946    pub fn has_table_filter(&self) -> bool {
8947        unsafe { ffi::rocksdb_readoptions_has_table_filter(self.inner.cast_const()) != 0 }
8948    }
8949
8950    /// Reads through the user defined index named by `value` instead of the standard
8951    /// block-based index.
8952    ///
8953    /// `value` goes through the `UserDefinedIndexFactory` object registry the same way
8954    /// [`BlockBasedOptions::set_user_defined_index_factory_from_string`] does, so it has to
8955    /// name the factory the SST files were written with. `trie_index` is the only factory
8956    /// RocksDB registers itself.
8957    ///
8958    /// Only needed while the UDI is a secondary index. With
8959    /// [`BlockBasedOptions::set_use_udi_as_primary_index`] on, every read already goes
8960    /// through the UDI and the factory from the table options wins over this one.
8961    ///
8962    /// # Errors
8963    ///
8964    /// Returns an error if `value` names no registered factory, or carries settings that
8965    /// factory rejects. Either way the previously configured factory is cleared first.
8966    pub fn set_table_index_factory_from_string(
8967        &mut self,
8968        value: impl AsRef<str>,
8969    ) -> Result<(), Error> {
8970        let value = value.as_ref();
8971        unsafe {
8972            ffi_try!(
8973                ffi::rocksdb_readoptions_set_table_index_factory_from_string(
8974                    self.inner,
8975                    value.as_ptr().cast::<c_char>(),
8976                    value.len(),
8977                )
8978            );
8979        }
8980        Ok(())
8981    }
8982
8983    /// Name of the configured user defined index factory, or `None` when there is none.
8984    ///
8985    /// This is the factory's registered id, not the full string passed to
8986    /// [`Self::set_table_index_factory_from_string`].
8987    pub fn get_table_index_factory_name(&self) -> Option<String> {
8988        let mut len: size_t = 0;
8989        let name = unsafe {
8990            ffi::rocksdb_readoptions_get_table_index_factory_name(
8991                self.inner.cast_const(),
8992                &raw mut len,
8993            )
8994        };
8995        if name.is_null() {
8996            return None;
8997        }
8998        Some(unsafe { borrowed_string(name, len) })
8999    }
9000
9001    /// Drops the user defined index factory, so reads go back to the standard index.
9002    ///
9003    /// See [`Self::set_table_index_factory_from_string`].
9004    pub fn clear_table_index_factory(&mut self) {
9005        unsafe {
9006            ffi::rocksdb_readoptions_clear_table_index_factory(self.inner);
9007        }
9008    }
9009
9010    /// Soft limit on the cumulative value size read by a single MultiGet, to bound how much
9011    /// it buffers. It always makes progress: at least one key is read even if its value alone
9012    /// exceeds the limit. Once the returned size exceeds the limit, subsequent keys get
9013    /// status Aborted (so a caller can retry them, and cannot loop forever on a single value
9014    /// that by itself exceeds the limit).
9015    pub fn set_value_size_soft_limit(&mut self, val: u64) {
9016        unsafe {
9017            ffi::rocksdb_readoptions_set_value_size_soft_limit(self.inner, val);
9018        }
9019    }
9020
9021    /// Returns the value of the `value_size_soft_limit` option.
9022    pub fn get_value_size_soft_limit(&self) -> u64 {
9023        unsafe { ffi::rocksdb_readoptions_get_value_size_soft_limit(self.inner) }
9024    }
9025
9026    /// Clears the merge operand count threshold, restoring the default of no limit.
9027    ///
9028    /// See [`Self::set_merge_operand_count_threshold`].
9029    pub fn clear_merge_operand_count_threshold(&mut self) {
9030        unsafe {
9031            ffi::rocksdb_readoptions_clear_merge_operand_count_threshold(self.inner);
9032        }
9033    }
9034
9035    /// Returns the current `async_io` setting.
9036    ///
9037    /// See [`Self::set_async_io`] for what this controls.
9038    pub fn get_async_io(&self) -> bool {
9039        unsafe { ffi::rocksdb_readoptions_get_async_io(self.inner) != 0 }
9040    }
9041
9042    /// Returns the current `background_purge_on_iterator_cleanup` setting.
9043    ///
9044    /// See [`Self::set_background_purge_on_iterator_cleanup`] for what this controls.
9045    pub fn get_background_purge_on_iterator_cleanup(&self) -> bool {
9046        unsafe {
9047            ffi::rocksdb_readoptions_get_background_purge_on_iterator_cleanup(self.inner) != 0
9048        }
9049    }
9050
9051    /// Returns the current `deadline` setting.
9052    ///
9053    /// See [`Self::set_deadline`] for what this controls.
9054    pub fn get_deadline(&self) -> u64 {
9055        unsafe { ffi::rocksdb_readoptions_get_deadline(self.inner) }
9056    }
9057
9058    /// Returns the current `fill_cache` setting.
9059    ///
9060    /// See [`Self::fill_cache`] for what this controls.
9061    pub fn get_fill_cache(&self) -> bool {
9062        unsafe { ffi::rocksdb_readoptions_get_fill_cache(self.inner) != 0 }
9063    }
9064
9065    /// Returns the current `io_timeout` setting.
9066    ///
9067    /// See [`Self::set_io_timeout`] for what this controls.
9068    pub fn get_io_timeout(&self) -> u64 {
9069        unsafe { ffi::rocksdb_readoptions_get_io_timeout(self.inner) }
9070    }
9071
9072    /// Returns the current `max_skippable_internal_keys` setting.
9073    ///
9074    /// See [`Self::set_max_skippable_internal_keys`] for what this controls.
9075    pub fn get_max_skippable_internal_keys(&self) -> u64 {
9076        unsafe { ffi::rocksdb_readoptions_get_max_skippable_internal_keys(self.inner) }
9077    }
9078
9079    /// Returns the current `pin_data` setting.
9080    ///
9081    /// See [`Self::set_pin_data`] for what this controls.
9082    pub fn get_pin_data(&self) -> bool {
9083        unsafe { ffi::rocksdb_readoptions_get_pin_data(self.inner) != 0 }
9084    }
9085
9086    /// Returns the current `prefix_same_as_start` setting.
9087    ///
9088    /// See [`Self::set_prefix_same_as_start`] for what this controls.
9089    pub fn get_prefix_same_as_start(&self) -> bool {
9090        unsafe { ffi::rocksdb_readoptions_get_prefix_same_as_start(self.inner) != 0 }
9091    }
9092
9093    /// Returns the current `readahead_size` setting.
9094    ///
9095    /// See [`Self::set_readahead_size`] for what this controls.
9096    pub fn get_readahead_size(&self) -> usize {
9097        unsafe { ffi::rocksdb_readoptions_get_readahead_size(self.inner) }
9098    }
9099
9100    /// Returns the current `tailing` setting.
9101    ///
9102    /// See [`Self::set_tailing`] for what this controls.
9103    pub fn get_tailing(&self) -> bool {
9104        unsafe { ffi::rocksdb_readoptions_get_tailing(self.inner) != 0 }
9105    }
9106
9107    /// Returns the current `total_order_seek` setting.
9108    ///
9109    /// See [`Self::set_total_order_seek`] for what this controls.
9110    pub fn get_total_order_seek(&self) -> bool {
9111        unsafe { ffi::rocksdb_readoptions_get_total_order_seek(self.inner) != 0 }
9112    }
9113
9114    /// Returns the current `verify_checksums` setting.
9115    ///
9116    /// See [`Self::set_verify_checksums`] for what this controls.
9117    pub fn get_verify_checksums(&self) -> bool {
9118        unsafe { ffi::rocksdb_readoptions_get_verify_checksums(self.inner) != 0 }
9119    }
9120
9121    /// Returns whether a merge operand count threshold is set.
9122    ///
9123    /// See [`Self::set_merge_operand_count_threshold`].
9124    pub fn has_merge_operand_count_threshold(&self) -> bool {
9125        unsafe { ffi::rocksdb_readoptions_has_merge_operand_count_threshold(self.inner) != 0 }
9126    }
9127}
9128
9129impl Default for ReadOptions {
9130    fn default() -> Self {
9131        unsafe {
9132            Self {
9133                inner: ffi::rocksdb_readoptions_create(),
9134                timestamp: None,
9135                iter_start_ts: None,
9136                iterate_upper_bound: None,
9137                iterate_lower_bound: None,
9138            }
9139        }
9140    }
9141}
9142
9143impl IngestExternalFileOptions {
9144    /// Can be set to true to move the files instead of copying them.
9145    pub fn set_move_files(&mut self, v: bool) {
9146        unsafe {
9147            ffi::rocksdb_ingestexternalfileoptions_set_move_files(self.inner, c_uchar::from(v));
9148        }
9149    }
9150
9151    /// If set to false, an ingested file keys could appear in existing snapshots
9152    /// that where created before the file was ingested.
9153    pub fn set_snapshot_consistency(&mut self, v: bool) {
9154        unsafe {
9155            ffi::rocksdb_ingestexternalfileoptions_set_snapshot_consistency(
9156                self.inner,
9157                c_uchar::from(v),
9158            );
9159        }
9160    }
9161
9162    /// If set to false, IngestExternalFile() will fail if the file key range
9163    /// overlaps with existing keys or tombstones in the DB.
9164    pub fn set_allow_global_seqno(&mut self, v: bool) {
9165        unsafe {
9166            ffi::rocksdb_ingestexternalfileoptions_set_allow_global_seqno(
9167                self.inner,
9168                c_uchar::from(v),
9169            );
9170        }
9171    }
9172
9173    /// If set to false and the file key range overlaps with the memtable key range
9174    /// (memtable flush required), IngestExternalFile will fail.
9175    pub fn set_allow_blocking_flush(&mut self, v: bool) {
9176        unsafe {
9177            ffi::rocksdb_ingestexternalfileoptions_set_allow_blocking_flush(
9178                self.inner,
9179                c_uchar::from(v),
9180            );
9181        }
9182    }
9183
9184    /// Set to true if you would like duplicate keys in the file being ingested
9185    /// to be skipped rather than overwriting existing data under that key.
9186    /// Usecase: back-fill of some historical data in the database without
9187    /// over-writing existing newer version of data.
9188    /// This option could only be used if the DB has been running
9189    /// with allow_ingest_behind=true since the dawn of time.
9190    /// All files will be ingested at the bottommost level with seqno=0.
9191    pub fn set_ingest_behind(&mut self, v: bool) {
9192        unsafe {
9193            ffi::rocksdb_ingestexternalfileoptions_set_ingest_behind(self.inner, c_uchar::from(v));
9194        }
9195    }
9196
9197    /// Normally (true), IngestExternalFile() will trigger and block for flushing memtable(s)
9198    /// if there is overlap between ingested files and memtable(s). If allow_blocking_flush is
9199    /// set to false, IngestExternalFile() will fail if the file key range overlaps with the
9200    /// memtable key range (memtable flush required).
9201    pub fn get_allow_blocking_flush(&self) -> bool {
9202        unsafe { ffi::rocksdb_ingestexternalfileoptions_get_allow_blocking_flush(self.inner) != 0 }
9203    }
9204
9205    /// EXPERIMENTAL, SUBJECT TO CHANGE
9206    ///
9207    /// Enables special mode of ingestion that allows files generated by a live DB, instead of
9208    /// SstFileWriter. When true:
9209    /// - Allows files to be ingested when their cf_id doesn't match the CF they are being
9210    ///   ingested into.
9211    /// - Allows files with any sequence numbers to be ingested.
9212    /// - Original sequence numbers are preserved (no reassignment).
9213    ///
9214    /// REQUIREMENTS:
9215    /// - Ingested files must NOT overlap with any existing data in the DB. Since no
9216    ///   sequence number reassignment is performed on db generated files. Ingestion will
9217    ///   fail if any overlap is detected. However, input files are allowed to overlap with
9218    ///   each other when this option is enabled. This is useful when ingesting multiple
9219    ///   levels of files from a CF, where levels naturally overlap with each other.
9220    /// - CAUTION: If input files overlap with each other, then for any given user key
9221    ///   appearing in multiple files, earlier files MUST have smaller sequence numbers than
9222    ///   later files. Later files will be placed at a higher level (smaller level number).
9223    ///   This is to ensure the LSM invariant where for the same key, recent updates are in
9224    ///   higher levels. This means that if you are ingesting files from multiple levels of
9225    ///   a CF, you should put files from lower levels first, and files from higher levels
9226    ///   later. Example for getting files from a CF for ingestion:
9227    ///
9228    /// ColumnFamilyMetaData cf_meta; from_db->GetColumnFamilyMetaData(from_cf, &cf_meta); //
9229    /// iterate in reverse to start from lowest level for (auto level_meta =
9230    /// cf_meta.levels.rbegin(); level_meta != cf_meta.levels.rend(); ++level_meta) { // L0
9231    /// files need to be added in reverse order so we iterate in reverse // within a level too
9232    /// for (auto file_meta = level_meta->files.rbegin(); file_meta !=
9233    /// level_meta->files.rend(); ++file_meta) { // Add file for ingestion } }
9234    ///
9235    /// WARNING: Violating the sequence number ordering requirement will cause LSM invariant
9236    /// violations and may lead to incorrect reads or data corruption.
9237    /// - If you would like to enforce that the ingested files do not overlap with each
9238    ///   other, you can set `fail_if_not_bottommost_level` to true. If ingested files
9239    ///   overlap with each other, some file will be placed above Lmax, failing the
9240    ///   ingestion if the option is set.
9241    /// - `write_global_seqno` must be false (sequence numbers cannot be reassigned).
9242    pub fn set_allow_db_generated_files(&mut self, val: bool) {
9243        unsafe {
9244            ffi::rocksdb_ingestexternalfileoptions_set_allow_db_generated_files(
9245                self.inner,
9246                c_uchar::from(val),
9247            );
9248        }
9249    }
9250
9251    /// Returns the value of the `allow_db_generated_files` option.
9252    pub fn get_allow_db_generated_files(&self) -> bool {
9253        unsafe {
9254            ffi::rocksdb_ingestexternalfileoptions_get_allow_db_generated_files(self.inner) != 0
9255        }
9256    }
9257
9258    /// Enables assiging a global sequence number to each ingested file, i.e., all keys in the
9259    /// ingested file will be treated as having this seqno. If set to false, we will use the
9260    /// sequence numbers in the ingested file as is, and IngestExternalFile() will fail if the
9261    /// ingested key range overlaps with existing keys or tombstones or output of ongoing
9262    /// compaction in the CF (the conditions under which a global seqno must be assigned to
9263    /// the ingested file). If the ingested files overlap with each other, we need to assign
9264    /// global sequence to the ingested files and this option needs to be enabled. One
9265    /// exception to this is when ingesting DB generated SST files (see option
9266    /// allow_db_generated_files below). DB generated files do not support global seqno
9267    /// assignment and can be ingested even if they overlap with each other. This option has
9268    /// no effect when allow_db_generated_files is enabled.
9269    pub fn get_allow_global_seqno(&self) -> bool {
9270        unsafe { ffi::rocksdb_ingestexternalfileoptions_get_allow_global_seqno(self.inner) != 0 }
9271    }
9272
9273    /// Set to TRUE if user wants file to be ingested to the last level. An error of
9274    /// Status::TryAgain() will be returned if a file cannot fit in the last level when
9275    /// calling DB::IngestExternalFile()/DB::IngestExternalFiles(). The user should clear the
9276    /// last level in the overlapping range before re-attempt.
9277    ///
9278    /// ingest_behind takes precedence over fail_if_not_bottommost_level.
9279    ///
9280    /// XXX: "bottommost" is obsolete/confusing terminology to refer to last level
9281    pub fn get_fail_if_not_bottommost_level(&self) -> bool {
9282        unsafe {
9283            ffi::rocksdb_ingestexternalfileoptions_get_fail_if_not_bottommost_level(self.inner) != 0
9284        }
9285    }
9286
9287    /// If set to true, ingestion falls back to copy when hard linking fails. This applies to
9288    /// both `move_files` and `link_files`.
9289    pub fn set_failed_move_fall_back_to_copy(&mut self, val: bool) {
9290        unsafe {
9291            ffi::rocksdb_ingestexternalfileoptions_set_failed_move_fall_back_to_copy(
9292                self.inner,
9293                c_uchar::from(val),
9294            );
9295        }
9296    }
9297
9298    /// Returns the value of the `failed_move_fall_back_to_copy` option.
9299    pub fn get_failed_move_fall_back_to_copy(&self) -> bool {
9300        unsafe {
9301            ffi::rocksdb_ingestexternalfileoptions_get_failed_move_fall_back_to_copy(self.inner)
9302                != 0
9303        }
9304    }
9305
9306    /// Maximum number of threads used to open table readers for the files being ingested
9307    /// during commit, can speed up ingestion performance, when ingesting multiple files at
9308    /// once.
9309    pub fn set_file_opening_threads(&mut self, val: c_int) {
9310        unsafe {
9311            ffi::rocksdb_ingestexternalfileoptions_set_file_opening_threads(self.inner, val);
9312        }
9313    }
9314
9315    /// Returns the value of the `file_opening_threads` option.
9316    pub fn get_file_opening_threads(&self) -> c_int {
9317        unsafe { ffi::rocksdb_ingestexternalfileoptions_get_file_opening_threads(self.inner) }
9318    }
9319
9320    /// Should the "data block"/"index block" read for this iteration be placed in block
9321    /// cache? Callers may wish to set this field to false for bulk scans. This would help not
9322    /// to the change eviction order of existing items in the block cache.
9323    pub fn set_fill_cache(&mut self, val: bool) {
9324        unsafe {
9325            ffi::rocksdb_ingestexternalfileoptions_set_fill_cache(self.inner, c_uchar::from(val));
9326        }
9327    }
9328
9329    /// Returns the value of the `fill_cache` option.
9330    pub fn get_fill_cache(&self) -> bool {
9331        unsafe { ffi::rocksdb_ingestexternalfileoptions_get_fill_cache(self.inner) != 0 }
9332    }
9333
9334    /// Set to true if you would like duplicate keys in the file being ingested to be skipped
9335    /// rather than overwriting existing data under that key. Use case: back-fill of some
9336    /// historical data in the database without over-writing existing newer version of data.
9337    /// This option could only be used if the CF has been running with
9338    /// cf_allow_ingest_behind=true since CF creation (or before any write). All files will be
9339    /// ingested at the bottommost level with seqno=0.
9340    pub fn get_ingest_behind(&self) -> bool {
9341        unsafe { ffi::rocksdb_ingestexternalfileoptions_get_ingest_behind(self.inner) != 0 }
9342    }
9343
9344    /// Same as move_files except that input files will NOT be unlinked. Only one of
9345    /// `move_files` and `link_files` can be set at the same time.
9346    pub fn set_link_files(&mut self, val: bool) {
9347        unsafe {
9348            ffi::rocksdb_ingestexternalfileoptions_set_link_files(self.inner, c_uchar::from(val));
9349        }
9350    }
9351
9352    /// Returns the value of the `link_files` option.
9353    pub fn get_link_files(&self) -> bool {
9354        unsafe { ffi::rocksdb_ingestexternalfileoptions_get_link_files(self.inner) != 0 }
9355    }
9356
9357    /// Can be set to true to move the files instead of copying them. The input files will be
9358    /// unlinked after successful ingestion. The implementation depends on hard links
9359    /// (LinkFile) instead of traditional move (RenameFile) to maximize the chances to restore
9360    /// to the original state upon failure.
9361    pub fn get_move_files(&self) -> bool {
9362        unsafe { ffi::rocksdb_ingestexternalfileoptions_get_move_files(self.inner) != 0 }
9363    }
9364
9365    /// Controls whether external file ingestion should prefetch index and filter blocks while
9366    /// opening table readers during commit. Setting this to false can reduce commit latency
9367    /// for bulk loads into Lmax when
9368    /// (BlockBasedTableOptions::cache_index_and_filter_blocks=true or partitioned
9369    /// filters/indexes are enabled).
9370    pub fn set_prefetch_lmax_index_and_filter_blocks(&mut self, val: bool) {
9371        unsafe {
9372            ffi::rocksdb_ingestexternalfileoptions_set_prefetch_lmax_index_and_filter_blocks(
9373                self.inner,
9374                c_uchar::from(val),
9375            );
9376        }
9377    }
9378
9379    /// Returns the value of the `prefetch_lmax_index_and_filter_blocks` option.
9380    pub fn get_prefetch_lmax_index_and_filter_blocks(&self) -> bool {
9381        unsafe {
9382            ffi::rocksdb_ingestexternalfileoptions_get_prefetch_lmax_index_and_filter_blocks(
9383                self.inner,
9384            ) != 0
9385        }
9386    }
9387
9388    /// If set to false, an ingested file keys could appear in existing snapshots that where
9389    /// created before the file was ingested.
9390    pub fn get_snapshot_consistency(&self) -> bool {
9391        unsafe { ffi::rocksdb_ingestexternalfileoptions_get_snapshot_consistency(self.inner) != 0 }
9392    }
9393
9394    /// Set to true if you would like to verify the checksums of each block of the external
9395    /// SST file before ingestion. Warning: setting this to true causes slowdown in file
9396    /// ingestion because the external SST file has to be read.
9397    pub fn set_verify_checksums_before_ingest(&mut self, val: bool) {
9398        unsafe {
9399            ffi::rocksdb_ingestexternalfileoptions_set_verify_checksums_before_ingest(
9400                self.inner,
9401                c_uchar::from(val),
9402            );
9403        }
9404    }
9405
9406    /// Returns the value of the `verify_checksums_before_ingest` option.
9407    pub fn get_verify_checksums_before_ingest(&self) -> bool {
9408        unsafe {
9409            ffi::rocksdb_ingestexternalfileoptions_get_verify_checksums_before_ingest(self.inner)
9410                != 0
9411        }
9412    }
9413
9414    /// When verify_checksums_before_ingest = true, RocksDB uses default readahead setting to
9415    /// scan the file while verifying checksums before ingestion. Users can override the
9416    /// default value using this option. Using a large readahead size (> 2MB) can typically
9417    /// improve the performance of forward iteration on spinning disks.
9418    pub fn set_verify_checksums_readahead_size(&mut self, val: usize) {
9419        unsafe {
9420            ffi::rocksdb_ingestexternalfileoptions_set_verify_checksums_readahead_size(
9421                self.inner, val,
9422            );
9423        }
9424    }
9425
9426    /// Returns the value of the `verify_checksums_readahead_size` option.
9427    pub fn get_verify_checksums_readahead_size(&self) -> usize {
9428        unsafe {
9429            ffi::rocksdb_ingestexternalfileoptions_get_verify_checksums_readahead_size(self.inner)
9430        }
9431    }
9432
9433    /// Set to TRUE if user wants to verify the sst file checksum of ingested files. The DB
9434    /// checksum function will generate the checksum of each ingested file (if
9435    /// file_checksum_gen_factory is set) and compare the checksum function name and checksum
9436    /// with the ingested checksum information.
9437    ///
9438    /// If this option is set to True: 1) if DB does not enable checksum
9439    /// (file_checksum_gen_factory == nullptr), the ingested checksum information will be
9440    /// ignored; 2) If DB enable the checksum function, we calculate the sst file checksum
9441    /// after the file is moved or copied and compare the checksum and checksum name. If
9442    /// checksum or checksum function name does not match, ingestion will be failed. If the
9443    /// verification is successful, checksum and checksum function name will be stored in
9444    /// Manifest. If this option is set to FALSE, 1) if DB does not enable checksum, the
9445    /// ingested checksum information will be ignored; 2) if DB enable the checksum, we only
9446    /// verify the ingested checksum function name and we trust the ingested checksum. If the
9447    /// checksum function name matches, we store the checksum in Manifest. DB does not
9448    /// calculate the checksum during ingestion. However, if no checksum information is
9449    /// provided with the ingested files, DB will generate the checksum and store in the
9450    /// Manifest.
9451    pub fn set_verify_file_checksum(&mut self, val: bool) {
9452        unsafe {
9453            ffi::rocksdb_ingestexternalfileoptions_set_verify_file_checksum(
9454                self.inner,
9455                c_uchar::from(val),
9456            );
9457        }
9458    }
9459
9460    /// Returns the value of the `verify_file_checksum` option.
9461    pub fn get_verify_file_checksum(&self) -> bool {
9462        unsafe { ffi::rocksdb_ingestexternalfileoptions_get_verify_file_checksum(self.inner) != 0 }
9463    }
9464
9465    /// DEPRECATED - Set to true if you would like to write global_seqno to the external SST
9466    /// file on ingestion for backward compatibility before RocksDB 5.16.0. Such old versions
9467    /// of RocksDB expect any global_seqno to be written to the SST file rather than recorded
9468    /// in the DB manifest. This functionality was deprecated because (a) random writes might
9469    /// be costly or unsupported on some FileSystems, and (b) the file checksum changes with
9470    /// such a write.
9471    pub fn set_write_global_seqno(&mut self, val: bool) {
9472        unsafe {
9473            ffi::rocksdb_ingestexternalfileoptions_set_write_global_seqno(
9474                self.inner,
9475                c_uchar::from(val),
9476            );
9477        }
9478    }
9479
9480    /// Returns the value of the `write_global_seqno` option.
9481    pub fn get_write_global_seqno(&self) -> bool {
9482        unsafe { ffi::rocksdb_ingestexternalfileoptions_get_write_global_seqno(self.inner) != 0 }
9483    }
9484
9485    /// Set to TRUE if user wants file to be ingested to the last level. An error of
9486    /// Status::TryAgain() will be returned if a file cannot fit in the last level when
9487    /// calling DB::IngestExternalFile()/DB::IngestExternalFiles(). The user should clear the
9488    /// last level in the overlapping range before re-attempt.
9489    ///
9490    /// ingest_behind takes precedence over fail_if_not_bottommost_level.
9491    ///
9492    /// XXX: "bottommost" is obsolete/confusing terminology to refer to last level.
9493    pub fn set_fail_if_not_bottommost_level(&mut self, val: bool) {
9494        unsafe {
9495            ffi::rocksdb_ingestexternalfileoptions_set_fail_if_not_bottommost_level(
9496                self.inner,
9497                c_uchar::from(val),
9498            );
9499        }
9500    }
9501}
9502
9503impl Default for IngestExternalFileOptions {
9504    fn default() -> Self {
9505        unsafe {
9506            Self {
9507                inner: ffi::rocksdb_ingestexternalfileoptions_create(),
9508            }
9509        }
9510    }
9511}
9512
9513/// Used by BlockBasedOptions::set_index_type.
9514pub enum BlockBasedIndexType {
9515    /// A space efficient index block that is optimized for
9516    /// binary-search-based index.
9517    BinarySearch = ffi::rocksdb_block_based_table_index_type_binary_search as isize,
9518
9519    /// The hash index, if enabled, will perform a hash lookup if
9520    /// a prefix extractor has been provided through Options::set_prefix_extractor.
9521    HashSearch = ffi::rocksdb_block_based_table_index_type_hash_search as isize,
9522
9523    /// A two-level index implementation. Both levels are binary search indexes.
9524    TwoLevelIndexSearch = ffi::rocksdb_block_based_table_index_type_two_level_index_search as isize,
9525}
9526
9527/// Used by BlockBasedOptions::set_data_block_index_type.
9528#[repr(C)]
9529pub enum DataBlockIndexType {
9530    /// Use binary search when performing point lookup for keys in data blocks.
9531    /// This is the default.
9532    BinarySearch = ffi::rocksdb_block_based_table_data_block_index_type_binary_search as isize,
9533
9534    /// Appends a compact hash table to the end of the data block for efficient indexing. Backwards
9535    /// compatible with databases created without this feature. Once turned on, existing data will
9536    /// be gradually converted to the hash index format.
9537    BinaryAndHash =
9538        ffi::rocksdb_block_based_table_data_block_index_type_binary_search_and_hash as isize,
9539}
9540
9541/// Defines the underlying memtable implementation.
9542/// See official [wiki](https://github.com/facebook/rocksdb/wiki/MemTable) for more information.
9543pub enum MemtableFactory {
9544    Vector,
9545    HashSkipList {
9546        bucket_count: usize,
9547        height: i32,
9548        branching_factor: i32,
9549    },
9550    HashLinkList {
9551        bucket_count: usize,
9552    },
9553}
9554
9555/// Used by BlockBasedOptions::set_checksum_type.
9556pub enum ChecksumType {
9557    NoChecksum = 0,
9558    CRC32c = 1,
9559    XXHash = 2,
9560    XXHash64 = 3,
9561    XXH3 = 4, // Supported since RocksDB 6.27
9562}
9563
9564/// Used in [`PlainTableFactoryOptions`].
9565#[derive(Debug, Copy, Clone, PartialEq, Eq, Default)]
9566pub enum KeyEncodingType {
9567    /// Always write full keys.
9568    #[default]
9569    Plain = 0,
9570    /// Find opportunities to write the same prefix for multiple rows.
9571    Prefix = 1,
9572}
9573
9574/// Used with DBOptions::set_plain_table_factory.
9575/// See official [wiki](https://github.com/facebook/rocksdb/wiki/PlainTable-Format) for more
9576/// information.
9577///
9578/// Defaults:
9579///  user_key_length: 0 (variable length)
9580///  bloom_bits_per_key: 10
9581///  hash_table_ratio: 0.75
9582///  index_sparseness: 16
9583///  huge_page_tlb_size: 0
9584///  encoding_type: KeyEncodingType::Plain
9585///  full_scan_mode: false
9586///  store_index_in_file: false
9587pub struct PlainTableFactoryOptions {
9588    pub user_key_length: u32,
9589    pub bloom_bits_per_key: i32,
9590    pub hash_table_ratio: f64,
9591    pub index_sparseness: usize,
9592    pub huge_page_tlb_size: usize,
9593    pub encoding_type: KeyEncodingType,
9594    pub full_scan_mode: bool,
9595    pub store_index_in_file: bool,
9596}
9597
9598#[derive(Debug, Copy, Clone, PartialEq, Eq)]
9599#[cfg_attr(feature = "serde1", derive(serde::Serialize, serde::Deserialize))]
9600pub enum DBCompressionType {
9601    None = ffi::rocksdb_no_compression as isize,
9602    Snappy = ffi::rocksdb_snappy_compression as isize,
9603    Zlib = ffi::rocksdb_zlib_compression as isize,
9604    Bz2 = ffi::rocksdb_bz2_compression as isize,
9605    Lz4 = ffi::rocksdb_lz4_compression as isize,
9606    Lz4hc = ffi::rocksdb_lz4hc_compression as isize,
9607    Zstd = ffi::rocksdb_zstd_compression as isize,
9608}
9609
9610impl DBCompressionType {
9611    /// Decodes a raw `rocksdb::CompressionType`.
9612    ///
9613    /// `None` for anything this crate does not name: xpress, which is Windows only, the
9614    /// `kCustomCompression*` range a `CompressionManager` can hand out, and the
9615    /// `kDisableCompressionOption` sentinel that `bottommost_compression` defaults to.
9616    pub(crate) fn try_from_raw(raw: c_int) -> Option<Self> {
9617        match raw {
9618            n if n == DBCompressionType::None as c_int => Some(DBCompressionType::None),
9619            n if n == DBCompressionType::Snappy as c_int => Some(DBCompressionType::Snappy),
9620            n if n == DBCompressionType::Zlib as c_int => Some(DBCompressionType::Zlib),
9621            n if n == DBCompressionType::Bz2 as c_int => Some(DBCompressionType::Bz2),
9622            n if n == DBCompressionType::Lz4 as c_int => Some(DBCompressionType::Lz4),
9623            n if n == DBCompressionType::Lz4hc as c_int => Some(DBCompressionType::Lz4hc),
9624            n if n == DBCompressionType::Zstd as c_int => Some(DBCompressionType::Zstd),
9625            _ => None,
9626        }
9627    }
9628}
9629
9630#[derive(Debug, Copy, Clone, PartialEq, Eq)]
9631#[cfg_attr(feature = "serde1", derive(serde::Serialize, serde::Deserialize))]
9632pub enum DBCompactionStyle {
9633    Level = ffi::rocksdb_level_compaction as isize,
9634    Universal = ffi::rocksdb_universal_compaction as isize,
9635    Fifo = ffi::rocksdb_fifo_compaction as isize,
9636}
9637
9638impl DBCompactionStyle {
9639    /// Decodes a raw `rocksdb::CompactionStyle`.
9640    ///
9641    /// `None` for `kCompactionStyleNone`, which this crate does not name.
9642    pub(crate) fn try_from_raw(raw: c_int) -> Option<Self> {
9643        match raw {
9644            n if n == DBCompactionStyle::Level as c_int => Some(DBCompactionStyle::Level),
9645            n if n == DBCompactionStyle::Universal as c_int => Some(DBCompactionStyle::Universal),
9646            n if n == DBCompactionStyle::Fifo as c_int => Some(DBCompactionStyle::Fifo),
9647            _ => None,
9648        }
9649    }
9650}
9651
9652#[derive(Debug, Copy, Clone, PartialEq, Eq)]
9653#[cfg_attr(feature = "serde1", derive(serde::Serialize, serde::Deserialize))]
9654pub enum DBRecoveryMode {
9655    TolerateCorruptedTailRecords = ffi::rocksdb_tolerate_corrupted_tail_records_recovery as isize,
9656    AbsoluteConsistency = ffi::rocksdb_absolute_consistency_recovery as isize,
9657    PointInTime = ffi::rocksdb_point_in_time_recovery as isize,
9658    SkipAnyCorruptedRecord = ffi::rocksdb_skip_any_corrupted_records_recovery as isize,
9659}
9660
9661impl DBRecoveryMode {
9662    /// Decodes a raw `rocksdb::WALRecoveryMode`.
9663    ///
9664    /// This covers every mode RocksDB defines today, so `None` only means a future release
9665    /// added one.
9666    pub(crate) fn try_from_raw(raw: c_int) -> Option<Self> {
9667        match raw {
9668            n if n == DBRecoveryMode::TolerateCorruptedTailRecords as c_int => {
9669                Some(DBRecoveryMode::TolerateCorruptedTailRecords)
9670            }
9671            n if n == DBRecoveryMode::AbsoluteConsistency as c_int => {
9672                Some(DBRecoveryMode::AbsoluteConsistency)
9673            }
9674            n if n == DBRecoveryMode::PointInTime as c_int => Some(DBRecoveryMode::PointInTime),
9675            n if n == DBRecoveryMode::SkipAnyCorruptedRecord as c_int => {
9676                Some(DBRecoveryMode::SkipAnyCorruptedRecord)
9677            }
9678            _ => None,
9679        }
9680    }
9681}
9682
9683#[derive(Debug, Copy, Clone, PartialEq, Eq)]
9684#[repr(i32)]
9685pub enum RateLimiterMode {
9686    KReadsOnly = 0,
9687    KWritesOnly = 1,
9688    KAllIo = 2,
9689}
9690
9691#[derive(Debug, Copy, Clone, PartialEq, Eq)]
9692#[cfg_attr(feature = "serde1", derive(serde::Serialize, serde::Deserialize))]
9693pub enum DBCompactionPri {
9694    ByCompensatedSize = ffi::rocksdb_k_by_compensated_size_compaction_pri as isize,
9695    OldestLargestSeqFirst = ffi::rocksdb_k_oldest_largest_seq_first_compaction_pri as isize,
9696    OldestSmallestSeqFirst = ffi::rocksdb_k_oldest_smallest_seq_first_compaction_pri as isize,
9697    MinOverlappingRatio = ffi::rocksdb_k_min_overlapping_ratio_compaction_pri as isize,
9698    RoundRobin = ffi::rocksdb_k_round_robin_compaction_pri as isize,
9699}
9700
9701impl DBCompactionPri {
9702    /// Decodes a raw `rocksdb::CompactionPri`.
9703    ///
9704    /// This covers every value RocksDB defines today, so `None` only means a future release
9705    /// added one.
9706    pub(crate) fn try_from_raw(raw: c_int) -> Option<Self> {
9707        match raw {
9708            n if n == DBCompactionPri::ByCompensatedSize as c_int => {
9709                Some(DBCompactionPri::ByCompensatedSize)
9710            }
9711            n if n == DBCompactionPri::OldestLargestSeqFirst as c_int => {
9712                Some(DBCompactionPri::OldestLargestSeqFirst)
9713            }
9714            n if n == DBCompactionPri::OldestSmallestSeqFirst as c_int => {
9715                Some(DBCompactionPri::OldestSmallestSeqFirst)
9716            }
9717            n if n == DBCompactionPri::MinOverlappingRatio as c_int => {
9718                Some(DBCompactionPri::MinOverlappingRatio)
9719            }
9720            n if n == DBCompactionPri::RoundRobin as c_int => Some(DBCompactionPri::RoundRobin),
9721            _ => None,
9722        }
9723    }
9724}
9725
9726/// Whether blobs written by a flush are inserted into the blob cache right away.
9727///
9728/// Used by [`Options::set_prepopulate_blob_cache`]. Mirrors `rocksdb::PrepopulateBlobCache`
9729/// from `include/rocksdb/advanced_options.h`, including its discriminants.
9730#[derive(Debug, Copy, Clone, PartialEq, Eq)]
9731#[cfg_attr(feature = "serde1", derive(serde::Serialize, serde::Deserialize))]
9732#[repr(i32)]
9733pub enum PrepopulateBlobCache {
9734    /// Blobs reach the cache only when something reads them. The default.
9735    Disable = ffi::rocksdb_prepopulate_blob_disable as i32,
9736    /// Blobs written by a flush go into the cache as they are written. Blobs written by
9737    /// compaction still do not.
9738    FlushOnly = ffi::rocksdb_prepopulate_blob_flush_only as i32,
9739}
9740
9741impl PrepopulateBlobCache {
9742    /// Decodes a raw `rocksdb::PrepopulateBlobCache`.
9743    ///
9744    /// This covers every value RocksDB defines today, so `None` only means a future release
9745    /// added one.
9746    pub(crate) fn try_from_raw(raw: c_int) -> Option<Self> {
9747        match raw {
9748            n if n == PrepopulateBlobCache::Disable as c_int => Some(PrepopulateBlobCache::Disable),
9749            n if n == PrepopulateBlobCache::FlushOnly as c_int => {
9750                Some(PrepopulateBlobCache::FlushOnly)
9751            }
9752            _ => None,
9753        }
9754    }
9755}
9756
9757#[derive(Debug, Copy, Clone, PartialEq, Eq)]
9758#[cfg_attr(feature = "serde1", derive(serde::Serialize, serde::Deserialize))]
9759pub enum BlockBasedPinningTier {
9760    Fallback = ffi::rocksdb_block_based_k_fallback_pinning_tier as isize,
9761    None = ffi::rocksdb_block_based_k_none_pinning_tier as isize,
9762    FlushAndSimilar = ffi::rocksdb_block_based_k_flush_and_similar_pinning_tier as isize,
9763    All = ffi::rocksdb_block_based_k_all_pinning_tier as isize,
9764}
9765
9766/// Index-block search algorithm selected by
9767/// [`BlockBasedOptions::set_index_block_search_type`].
9768///
9769/// `Auto` is only meaningful in combination with
9770/// [`BlockBasedOptions::set_uniform_cv_threshold`]: the threshold gates whether
9771/// the per-block "is_uniform" footer bit is set on the write path, and `Auto`
9772/// reads that bit at lookup time to choose between binary and interpolation
9773/// search per index block. Without setting the threshold to a non-negative
9774/// value, `Auto` degenerates to binary search.
9775#[derive(Debug, Copy, Clone, PartialEq, Eq)]
9776#[cfg_attr(feature = "serde1", derive(serde::Serialize, serde::Deserialize))]
9777pub enum IndexBlockSearchType {
9778    /// Standard binary search. The default and safest choice.
9779    Binary = ffi::rocksdb_block_based_table_index_block_search_type_binary as isize,
9780    /// Interpolation search. Faster than binary search for index blocks whose
9781    /// keys are uniformly distributed; significantly slower when they are not.
9782    ///
9783    /// Only applicable when the byte-wise comparator is in use; with any
9784    /// other comparator the C++ code falls back to binary search regardless.
9785    ///
9786    /// Performance is significantly degraded when
9787    /// `IndexShorteningMode::kShortenSeparatorsAndSuccessor` is also set,
9788    /// because the shortened successor skews end-keys away from the uniform
9789    /// distribution that interpolation search relies on. Avoid combining the
9790    /// two.
9791    Interpolation = ffi::rocksdb_block_based_table_index_block_search_type_interpolation as isize,
9792    /// Per-block adaptive selection between binary and interpolation search,
9793    /// based on the per-block "is_uniform" footer bit. Requires
9794    /// `uniform_cv_threshold >= 0` on the write path; see
9795    /// [`BlockBasedOptions::set_uniform_cv_threshold`].
9796    Auto = ffi::rocksdb_block_based_table_index_block_search_type_auto as isize,
9797}
9798
9799pub struct FifoCompactOptions {
9800    pub(crate) inner: *mut ffi::rocksdb_fifo_compaction_options_t,
9801}
9802
9803impl Default for FifoCompactOptions {
9804    fn default() -> Self {
9805        let opts = unsafe { ffi::rocksdb_fifo_compaction_options_create() };
9806        assert!(
9807            !opts.is_null(),
9808            "Could not create RocksDB Fifo Compaction Options"
9809        );
9810
9811        Self { inner: opts }
9812    }
9813}
9814
9815impl Drop for FifoCompactOptions {
9816    fn drop(&mut self) {
9817        unsafe {
9818            ffi::rocksdb_fifo_compaction_options_destroy(self.inner);
9819        }
9820    }
9821}
9822
9823impl FifoCompactOptions {
9824    /// Sets the max table file size.
9825    ///
9826    /// Once the total sum of table files reaches this, we will delete the oldest
9827    /// table file
9828    ///
9829    /// Default: 1GB
9830    pub fn set_max_table_files_size(&mut self, nbytes: u64) {
9831        unsafe {
9832            ffi::rocksdb_fifo_compaction_options_set_max_table_files_size(self.inner, nbytes);
9833        }
9834    }
9835
9836    /// DEPRECATED When not 0, if the data in the file is older than this threshold, RocksDB
9837    /// will soon move the file to warm temperature.
9838    pub fn set_age_for_warm(&mut self, val: u64) {
9839        unsafe {
9840            ffi::rocksdb_fifo_compaction_options_set_age_for_warm(self.inner, val);
9841        }
9842    }
9843
9844    /// Returns the value of the `age_for_warm` option.
9845    pub fn get_age_for_warm(&self) -> u64 {
9846        unsafe { ffi::rocksdb_fifo_compaction_options_get_age_for_warm(self.inner) }
9847    }
9848
9849    /// EXPERIMENTAL If true, when compaction is picked for kChangeTemperature reason, allow
9850    /// the trivia copy of the sst file from source FileSystem to destination FileSystem. If
9851    /// false, the changeTemperature will be the non-trivial copy by iterating/appending
9852    /// blocks by blocks of the sst file.
9853    pub fn set_allow_trivial_copy_when_change_temperature(&mut self, val: bool) {
9854        unsafe {
9855            ffi::rocksdb_fifo_compaction_options_set_allow_trivial_copy_when_change_temperature(
9856                self.inner,
9857                c_uchar::from(val),
9858            );
9859        }
9860    }
9861
9862    /// Returns the value of the `allow_trivial_copy_when_change_temperature` option.
9863    pub fn get_allow_trivial_copy_when_change_temperature(&self) -> bool {
9864        unsafe {
9865            ffi::rocksdb_fifo_compaction_options_get_allow_trivial_copy_when_change_temperature(
9866                self.inner,
9867            ) != 0
9868        }
9869    }
9870
9871    /// EXPERIMENTAL If 'allow_trivia_copy_op_when_change_temperature=true', the tmp buffer
9872    /// size to copy the file from the source FileSystem to the destnation FileSystem. If
9873    /// 'allow_trivia_copy_op_when_change_temperature=false', this field will not be used. The
9874    /// minmum buffer size must be at least 4KiB
9875    pub fn set_trivial_copy_buffer_size(&mut self, val: u64) {
9876        unsafe {
9877            ffi::rocksdb_fifo_compaction_options_set_trivial_copy_buffer_size(self.inner, val);
9878        }
9879    }
9880
9881    /// Returns the value of the `trivial_copy_buffer_size` option.
9882    pub fn get_trivial_copy_buffer_size(&self) -> u64 {
9883        unsafe { ffi::rocksdb_fifo_compaction_options_get_trivial_copy_buffer_size(self.inner) }
9884    }
9885
9886    /// Returns the current `allow_compaction` setting.
9887    ///
9888    /// See [`Self::set_allow_compaction`] for what this controls.
9889    pub fn get_allow_compaction(&self) -> bool {
9890        unsafe { ffi::rocksdb_fifo_compaction_options_get_allow_compaction(self.inner) != 0 }
9891    }
9892
9893    /// Returns the current `max_data_files_size` setting.
9894    ///
9895    /// See [`Self::set_max_data_files_size`] for what this controls.
9896    pub fn get_max_data_files_size(&self) -> u64 {
9897        unsafe { ffi::rocksdb_fifo_compaction_options_get_max_data_files_size(self.inner) }
9898    }
9899
9900    /// Returns the current `max_table_files_size` setting.
9901    ///
9902    /// See [`Self::set_max_table_files_size`] for what this controls.
9903    pub fn get_max_table_files_size(&self) -> u64 {
9904        unsafe { ffi::rocksdb_fifo_compaction_options_get_max_table_files_size(self.inner) }
9905    }
9906
9907    /// Returns the current `use_kv_ratio_compaction` setting.
9908    ///
9909    /// See [`Self::set_use_kv_ratio_compaction`] for what this controls.
9910    pub fn get_use_kv_ratio_compaction(&self) -> bool {
9911        unsafe { ffi::rocksdb_fifo_compaction_options_get_use_kv_ratio_compaction(self.inner) != 0 }
9912    }
9913
9914    /// If true, try to do compaction to compact smaller files into larger ones. Minimum files
9915    /// to compact follows options.level0_file_num_compaction_trigger and compaction won't
9916    /// trigger if average compact bytes per del file is larger than
9917    /// options.write_buffer_size. This is to protect large files from being compacted again.
9918    /// Default: false;
9919    pub fn set_allow_compaction(&mut self, val: bool) {
9920        unsafe {
9921            ffi::rocksdb_fifo_compaction_options_set_allow_compaction(
9922                self.inner,
9923                c_uchar::from(val),
9924            );
9925        }
9926    }
9927
9928    /// When non-zero, FIFO compaction uses the combined size of SST files and blob files for
9929    /// size-based trimming decisions. When the total data size (SST + blob) exceeds this
9930    /// limit, the oldest SST files are dropped along with their associated blob files.
9931    ///
9932    /// When non-zero, this takes precedence over max_table_files_size for all FIFO compaction
9933    /// decisions: size-based dropping, TTL threshold checks, and compaction score
9934    /// computation. max_table_files_size is ignored.
9935    ///
9936    /// When zero (default), FIFO compaction uses max_table_files_size which only considers
9937    /// SST file sizes, maintaining backward compatibility.
9938    ///
9939    /// This option is primarily intended for use with integrated BlobDB where blob files can
9940    /// represent a significant portion of the total data.
9941    ///
9942    /// Dynamically changeable through SetOptions() API. Default: 0 (use max_table_files_size
9943    /// behavior).
9944    pub fn set_max_data_files_size(&mut self, val: u64) {
9945        unsafe {
9946            ffi::rocksdb_fifo_compaction_options_set_max_data_files_size(self.inner, val);
9947        }
9948    }
9949
9950    /// When true, enables a capacity-derived intra-L0 compaction strategy optimized for
9951    /// BlobDB workloads where SST files are much smaller than write_buffer_size. Uses the
9952    /// observed key/value size ratio (SST vs blob file sizes) to compute a target compacted
9953    /// file size, producing uniform files for predictable FIFO trimming.
9954    ///
9955    /// Uses level0_file_num_compaction_trigger as the target max L0 file count.
9956    ///
9957    /// When max_compaction_bytes is 0, the target is auto-calculated from the data capacity
9958    /// and observed SST/blob ratio. When max_compaction_bytes is explicitly set to a non-zero
9959    /// value, it overrides the auto-calculated target.
9960    ///
9961    /// Recommends:
9962    /// - allow_compaction = true (master switch for intra-L0 compaction)
9963    /// - max_data_files_size > 0 (needed to compute the target file size) If these are not
9964    ///   met, kv_ratio compaction is skipped and the old cost-based intra-L0 compaction
9965    ///   algorithm is used as a fallback.
9966    ///
9967    /// When false, the old intra-L0 strategy is used if allow_compaction is true
9968    /// (PickCostBasedIntraL0Compaction with 1.1 * write_buffer_size guard).
9969    ///
9970    /// Dynamically changeable through SetOptions() API. Default: false.
9971    pub fn set_use_kv_ratio_compaction(&mut self, val: bool) {
9972        unsafe {
9973            ffi::rocksdb_fifo_compaction_options_set_use_kv_ratio_compaction(
9974                self.inner,
9975                c_uchar::from(val),
9976            );
9977        }
9978    }
9979}
9980
9981#[derive(Debug, Copy, Clone, PartialEq, Eq)]
9982#[cfg_attr(feature = "serde1", derive(serde::Serialize, serde::Deserialize))]
9983pub enum UniversalCompactionStopStyle {
9984    Similar = ffi::rocksdb_similar_size_compaction_stop_style as isize,
9985    Total = ffi::rocksdb_total_size_compaction_stop_style as isize,
9986}
9987
9988impl UniversalCompactionStopStyle {
9989    /// Decodes a raw `rocksdb::CompactionStopStyle`.
9990    pub(crate) fn try_from_raw(raw: c_int) -> Option<Self> {
9991        match raw {
9992            n if n == UniversalCompactionStopStyle::Similar as c_int => {
9993                Some(UniversalCompactionStopStyle::Similar)
9994            }
9995            n if n == UniversalCompactionStopStyle::Total as c_int => {
9996                Some(UniversalCompactionStopStyle::Total)
9997            }
9998            _ => None,
9999        }
10000    }
10001}
10002
10003pub struct UniversalCompactOptions {
10004    pub(crate) inner: *mut ffi::rocksdb_universal_compaction_options_t,
10005}
10006
10007impl Default for UniversalCompactOptions {
10008    fn default() -> Self {
10009        let opts = unsafe { ffi::rocksdb_universal_compaction_options_create() };
10010        assert!(
10011            !opts.is_null(),
10012            "Could not create RocksDB Universal Compaction Options"
10013        );
10014
10015        Self { inner: opts }
10016    }
10017}
10018
10019impl Drop for UniversalCompactOptions {
10020    fn drop(&mut self) {
10021        unsafe {
10022            ffi::rocksdb_universal_compaction_options_destroy(self.inner);
10023        }
10024    }
10025}
10026
10027impl UniversalCompactOptions {
10028    /// Sets the percentage flexibility while comparing file size.
10029    /// If the candidate file(s) size is 1% smaller than the next file's size,
10030    /// then include next file into this candidate set.
10031    ///
10032    /// Default: 1
10033    pub fn set_size_ratio(&mut self, ratio: c_int) {
10034        unsafe {
10035            ffi::rocksdb_universal_compaction_options_set_size_ratio(self.inner, ratio);
10036        }
10037    }
10038
10039    /// Sets the minimum number of files in a single compaction run.
10040    ///
10041    /// Default: 2
10042    pub fn set_min_merge_width(&mut self, num: c_int) {
10043        unsafe {
10044            ffi::rocksdb_universal_compaction_options_set_min_merge_width(self.inner, num);
10045        }
10046    }
10047
10048    /// Sets the maximum number of files in a single compaction run.
10049    ///
10050    /// Default: UINT_MAX
10051    pub fn set_max_merge_width(&mut self, num: c_int) {
10052        unsafe {
10053            ffi::rocksdb_universal_compaction_options_set_max_merge_width(self.inner, num);
10054        }
10055    }
10056
10057    /// sets the size amplification.
10058    ///
10059    /// It is defined as the amount (in percentage) of
10060    /// additional storage needed to store a single byte of data in the database.
10061    /// For example, a size amplification of 2% means that a database that
10062    /// contains 100 bytes of user-data may occupy upto 102 bytes of
10063    /// physical storage. By this definition, a fully compacted database has
10064    /// a size amplification of 0%. Rocksdb uses the following heuristic
10065    /// to calculate size amplification: it assumes that all files excluding
10066    /// the earliest file contribute to the size amplification.
10067    ///
10068    /// Default: 200, which means that a 100 byte database could require upto 300 bytes of storage.
10069    pub fn set_max_size_amplification_percent(&mut self, v: c_int) {
10070        unsafe {
10071            ffi::rocksdb_universal_compaction_options_set_max_size_amplification_percent(
10072                self.inner, v,
10073            );
10074        }
10075    }
10076
10077    /// Sets the percentage of compression size.
10078    ///
10079    /// If this option is set to be -1, all the output files
10080    /// will follow compression type specified.
10081    ///
10082    /// If this option is not negative, we will try to make sure compressed
10083    /// size is just above this value. In normal cases, at least this percentage
10084    /// of data will be compressed.
10085    /// When we are compacting to a new file, here is the criteria whether
10086    /// it needs to be compressed: assuming here are the list of files sorted
10087    /// by generation time:
10088    ///    A1...An B1...Bm C1...Ct
10089    /// where A1 is the newest and Ct is the oldest, and we are going to compact
10090    /// B1...Bm, we calculate the total size of all the files as total_size, as
10091    /// well as  the total size of C1...Ct as total_C, the compaction output file
10092    /// will be compressed iff
10093    ///   total_C / total_size < this percentage
10094    ///
10095    /// Default: -1
10096    pub fn set_compression_size_percent(&mut self, v: c_int) {
10097        unsafe {
10098            ffi::rocksdb_universal_compaction_options_set_compression_size_percent(self.inner, v);
10099        }
10100    }
10101
10102    /// Sets the algorithm used to stop picking files into a single compaction run.
10103    ///
10104    /// Default: ::Total
10105    pub fn set_stop_style(&mut self, style: UniversalCompactionStopStyle) {
10106        unsafe {
10107            ffi::rocksdb_universal_compaction_options_set_stop_style(self.inner, style as c_int);
10108        }
10109    }
10110
10111    /// The stop style set by [`Self::set_stop_style`].
10112    ///
10113    /// [`UniversalCompactionStopStyle`] covers both styles RocksDB defines
10114    /// today, so `None` only shows up if a future release adds one.
10115    pub fn get_stop_style(&self) -> Option<UniversalCompactionStopStyle> {
10116        let raw = unsafe { ffi::rocksdb_universal_compaction_options_get_stop_style(self.inner) };
10117        UniversalCompactionStopStyle::try_from_raw(raw)
10118    }
10119
10120    /// Option to optimize the manual compaction by enabling trivial move for non overlapping
10121    /// files. Default: false
10122    pub fn set_allow_trivial_move(&mut self, val: bool) {
10123        unsafe {
10124            ffi::rocksdb_universal_compaction_options_set_allow_trivial_move(
10125                self.inner,
10126                c_uchar::from(val),
10127            );
10128        }
10129    }
10130
10131    /// Returns the value of the `allow_trivial_move` option.
10132    pub fn get_allow_trivial_move(&self) -> bool {
10133        unsafe { ffi::rocksdb_universal_compaction_options_get_allow_trivial_move(self.inner) != 0 }
10134    }
10135
10136    /// EXPERIMENTAL If true, try to limit compaction size under max_compaction_bytes. This
10137    /// might cause higher write amplification, but can prevent some problem caused by large
10138    /// compactions. Default: false
10139    pub fn set_incremental(&mut self, val: bool) {
10140        unsafe {
10141            ffi::rocksdb_universal_compaction_options_set_incremental(
10142                self.inner,
10143                c_uchar::from(val),
10144            );
10145        }
10146    }
10147
10148    /// Returns the value of the `incremental` option.
10149    pub fn get_incremental(&self) -> bool {
10150        unsafe { ffi::rocksdb_universal_compaction_options_get_incremental(self.inner) != 0 }
10151    }
10152
10153    /// The limit on the number of sorted runs. RocksDB will try to keep the number of sorted
10154    /// runs at most this number. While compactions are running, the number of sorted runs may
10155    /// be temporarily higher than this number.
10156    ///
10157    /// Since universal compaction checks if there is compaction to do when the number of
10158    /// sorted runs is at least level0_file_num_compaction_trigger, it is suggested to set
10159    /// level0_file_num_compaction_trigger to be no larger than max_read_amp.
10160    ///
10161    /// Values: -1: special flag to let RocksDB pick default. Currently, RocksDB will fall
10162    /// back to the behavior before this option is introduced, which is to use
10163    /// level0_file_num_compaction_trigger as the limit. This may change in the future to
10164    /// behave as 0 below. 0: Let RocksDB auto-tune. Currently, we determine the max number of
10165    /// sorted runs based on the current DB size, size_ratio and write_buffer_size. Note that
10166    /// this is only supported for the default stop_style kCompactionStopStyleTotalSize. For
10167    /// kCompactionStopStyleSimilarSize, this behaves as if -1 is configured. N > 0: limit the
10168    /// number of sorted runs to be at most N. N should be at least the compaction trigger
10169    /// specified by level0_file_num_compaction_trigger. If 0 < max_read_amp <
10170    /// level0_file_num_compaction_trigger, Status::NotSupported() will be returned during DB
10171    /// open. N < -1: Status::NotSupported() will be returned during DB open.
10172    ///
10173    /// Default: -1
10174    pub fn set_max_read_amp(&mut self, val: c_int) {
10175        unsafe {
10176            ffi::rocksdb_universal_compaction_options_set_max_read_amp(self.inner, val);
10177        }
10178    }
10179
10180    /// Returns the value of the `max_read_amp` option.
10181    pub fn get_max_read_amp(&self) -> c_int {
10182        unsafe { ffi::rocksdb_universal_compaction_options_get_max_read_amp(self.inner) }
10183    }
10184
10185    /// If true, auto universal compaction picking will adjust to minimize locking of input
10186    /// files when bottom priority compactions are waiting to run. This can increase the
10187    /// likelihood of existing L0s being selected for compaction, thereby improving write
10188    /// stall and reducing read regression. It may increase the overrall write amplification
10189    /// and compaction load on low priority threads.
10190    ///
10191    /// Default: true (enabled)
10192    ///
10193    /// This options does not apply to manual compactions.
10194    ///
10195    /// This option is temporary in case turning on this feature causes problems and users
10196    /// need to undo it quickly. This option is planned for removal in the near future with
10197    /// default value set to true.
10198    ///
10199    /// Dynamically changeable through the SetOptions() API.
10200    pub fn set_reduce_file_locking(&mut self, val: bool) {
10201        unsafe {
10202            ffi::rocksdb_universal_compaction_options_set_reduce_file_locking(
10203                self.inner,
10204                c_uchar::from(val),
10205            );
10206        }
10207    }
10208
10209    /// Returns the value of the `reduce_file_locking` option.
10210    pub fn get_reduce_file_locking(&self) -> bool {
10211        unsafe {
10212            ffi::rocksdb_universal_compaction_options_get_reduce_file_locking(self.inner) != 0
10213        }
10214    }
10215
10216    /// Returns the current `compression_size_percent` setting.
10217    ///
10218    /// See [`Self::set_compression_size_percent`] for what this controls.
10219    pub fn get_compression_size_percent(&self) -> c_int {
10220        unsafe {
10221            ffi::rocksdb_universal_compaction_options_get_compression_size_percent(self.inner)
10222        }
10223    }
10224
10225    /// Returns the current `max_merge_width` setting.
10226    ///
10227    /// See [`Self::set_max_merge_width`] for what this controls.
10228    pub fn get_max_merge_width(&self) -> c_int {
10229        unsafe { ffi::rocksdb_universal_compaction_options_get_max_merge_width(self.inner) }
10230    }
10231
10232    /// Returns the current `max_size_amplification_percent` setting.
10233    ///
10234    /// See [`Self::set_max_size_amplification_percent`] for what this controls.
10235    pub fn get_max_size_amplification_percent(&self) -> c_int {
10236        unsafe {
10237            ffi::rocksdb_universal_compaction_options_get_max_size_amplification_percent(self.inner)
10238        }
10239    }
10240
10241    /// Returns the current `min_merge_width` setting.
10242    ///
10243    /// See [`Self::set_min_merge_width`] for what this controls.
10244    pub fn get_min_merge_width(&self) -> c_int {
10245        unsafe { ffi::rocksdb_universal_compaction_options_get_min_merge_width(self.inner) }
10246    }
10247
10248    /// Returns the current `size_ratio` setting.
10249    ///
10250    /// See [`Self::set_size_ratio`] for what this controls.
10251    pub fn get_size_ratio(&self) -> c_int {
10252        unsafe { ffi::rocksdb_universal_compaction_options_get_size_ratio(self.inner) }
10253    }
10254}
10255
10256#[derive(Debug, Copy, Clone, PartialEq, Eq)]
10257#[cfg_attr(feature = "serde1", derive(serde::Serialize, serde::Deserialize))]
10258#[repr(u8)]
10259pub enum BottommostLevelCompaction {
10260    /// Skip bottommost level compaction
10261    Skip = 0,
10262    /// Only compact bottommost level if there is a compaction filter
10263    /// This is the default option
10264    IfHaveCompactionFilter,
10265    /// Always compact bottommost level
10266    Force,
10267    /// Always compact bottommost level but in bottommost level avoid
10268    /// double-compacting files created in the same compaction
10269    ForceOptimized,
10270}
10271
10272pub struct CompactOptions {
10273    pub(crate) inner: *mut ffi::rocksdb_compactoptions_t,
10274    full_history_ts_low: Option<Vec<u8>>,
10275}
10276
10277impl Default for CompactOptions {
10278    fn default() -> Self {
10279        let opts = unsafe { ffi::rocksdb_compactoptions_create() };
10280        assert!(!opts.is_null(), "Could not create RocksDB Compact Options");
10281
10282        Self {
10283            inner: opts,
10284            full_history_ts_low: None,
10285        }
10286    }
10287}
10288
10289impl Drop for CompactOptions {
10290    fn drop(&mut self) {
10291        unsafe {
10292            ffi::rocksdb_compactoptions_destroy(self.inner);
10293        }
10294    }
10295}
10296
10297impl CompactOptions {
10298    /// If more than one thread calls manual compaction,
10299    /// only one will actually schedule it while the other threads will simply wait
10300    /// for the scheduled manual compaction to complete. If exclusive_manual_compaction
10301    /// is set to true, the call will disable scheduling of automatic compaction jobs
10302    /// and wait for existing automatic compaction jobs to finish.
10303    pub fn set_exclusive_manual_compaction(&mut self, v: bool) {
10304        unsafe {
10305            ffi::rocksdb_compactoptions_set_exclusive_manual_compaction(
10306                self.inner,
10307                c_uchar::from(v),
10308            );
10309        }
10310    }
10311
10312    /// Sets bottommost level compaction.
10313    pub fn set_bottommost_level_compaction(&mut self, lvl: BottommostLevelCompaction) {
10314        unsafe {
10315            ffi::rocksdb_compactoptions_set_bottommost_level_compaction(self.inner, lvl as c_uchar);
10316        }
10317    }
10318
10319    /// If true, compacted files will be moved to the minimum level capable
10320    /// of holding the data or given level (specified non-negative target_level).
10321    pub fn set_change_level(&mut self, v: bool) {
10322        unsafe {
10323            ffi::rocksdb_compactoptions_set_change_level(self.inner, c_uchar::from(v));
10324        }
10325    }
10326
10327    /// If change_level is true and target_level have non-negative value, compacted
10328    /// files will be moved to target_level.
10329    pub fn set_target_level(&mut self, lvl: c_int) {
10330        unsafe {
10331            ffi::rocksdb_compactoptions_set_target_level(self.inner, lvl);
10332        }
10333    }
10334
10335    /// Set user-defined timestamp low bound, the data with older timestamp than
10336    /// low bound maybe GCed by compaction. Default: nullptr
10337    pub fn set_full_history_ts_low<S: Into<Vec<u8>>>(&mut self, ts: S) {
10338        self.set_full_history_ts_low_impl(Some(ts.into()));
10339    }
10340
10341    fn set_full_history_ts_low_impl(&mut self, ts: Option<Vec<u8>>) {
10342        let (ptr, len) = if let Some(ref ts) = ts {
10343            (ts.as_ptr().cast_mut().cast::<c_char>(), ts.len())
10344        } else if self.full_history_ts_low.is_some() {
10345            (std::ptr::null::<Vec<u8>>() as *mut c_char, 0)
10346        } else {
10347            return;
10348        };
10349        self.full_history_ts_low = ts;
10350        unsafe {
10351            ffi::rocksdb_compactoptions_set_full_history_ts_low(self.inner, ptr, len);
10352        }
10353    }
10354
10355    /// Override `CompactRangeOptions::blob_garbage_collection_age_cutoff` for a
10356    /// single manual compaction.
10357    ///
10358    /// If set to `< 0` or `> 1`, RocksDB leaves the
10359    /// `blob_garbage_collection_age_cutoff` from `ColumnFamilyOptions` in
10360    /// effect (this is the default, `-1`). Otherwise, it overrides the
10361    /// user-provided setting for the duration of this compaction. This
10362    /// enables callers to selectively override the age cutoff per
10363    /// `compact_range` call.
10364    ///
10365    /// See [`Options::set_blob_gc_age_cutoff`] for the CF-level setter that
10366    /// this value overrides.
10367    pub fn set_blob_garbage_collection_age_cutoff(&mut self, v: c_double) {
10368        unsafe {
10369            ffi::rocksdb_compactoptions_set_blob_garbage_collection_age_cutoff(self.inner, v);
10370        }
10371    }
10372
10373    /// If set to < 0 or > 1, RocksDB leaves blob_garbage_collection_age_cutoff from
10374    /// ColumnFamilyOptions in effect. Otherwise, it will override the user-provided setting.
10375    /// This enables customers to selectively override the age cutoff.
10376    pub fn get_blob_garbage_collection_age_cutoff(&self) -> f64 {
10377        unsafe { ffi::rocksdb_compactoptions_get_blob_garbage_collection_age_cutoff(self.inner) }
10378    }
10379
10380    /// If set to kForce, RocksDB will override enable_blob_file_garbage_collection to true;
10381    /// if set to kDisable, RocksDB will override it to false, and kUseDefault leaves the
10382    /// setting in effect. This enables customers to both force-enable and force-disable GC
10383    /// when calling CompactRange.
10384    pub fn set_blob_garbage_collection_policy(&mut self, val: c_int) {
10385        unsafe {
10386            ffi::rocksdb_compactoptions_set_blob_garbage_collection_policy(self.inner, val);
10387        }
10388    }
10389
10390    /// Returns the value of the `blob_garbage_collection_policy` option.
10391    pub fn get_blob_garbage_collection_policy(&self) -> c_int {
10392        unsafe { ffi::rocksdb_compactoptions_get_blob_garbage_collection_policy(self.inner) }
10393    }
10394
10395    /// Returns the current `allow_write_stall` setting.
10396    ///
10397    /// See [`Self::set_allow_write_stall`] for what this controls.
10398    pub fn get_allow_write_stall(&self) -> bool {
10399        unsafe { ffi::rocksdb_compactoptions_get_allow_write_stall(self.inner) != 0 }
10400    }
10401
10402    /// Returns the current `bottommost_level_compaction` setting.
10403    ///
10404    /// See [`Self::set_bottommost_level_compaction`] for what this controls.
10405    pub fn get_bottommost_level_compaction(&self) -> bool {
10406        unsafe { ffi::rocksdb_compactoptions_get_bottommost_level_compaction(self.inner) != 0 }
10407    }
10408
10409    /// Returns the current `change_level` setting.
10410    ///
10411    /// See [`Self::set_change_level`] for what this controls.
10412    pub fn get_change_level(&self) -> bool {
10413        unsafe { ffi::rocksdb_compactoptions_get_change_level(self.inner) != 0 }
10414    }
10415
10416    /// Returns the current `exclusive_manual_compaction` setting.
10417    ///
10418    /// See [`Self::set_exclusive_manual_compaction`] for what this controls.
10419    pub fn get_exclusive_manual_compaction(&self) -> bool {
10420        unsafe { ffi::rocksdb_compactoptions_get_exclusive_manual_compaction(self.inner) != 0 }
10421    }
10422
10423    /// Returns the current `max_subcompactions` setting.
10424    ///
10425    /// See [`Self::set_max_subcompactions`] for what this controls.
10426    pub fn get_max_subcompactions(&self) -> c_int {
10427        unsafe { ffi::rocksdb_compactoptions_get_max_subcompactions(self.inner) }
10428    }
10429
10430    /// Returns the current `target_level` setting.
10431    ///
10432    /// See [`Self::set_target_level`] for what this controls.
10433    pub fn get_target_level(&self) -> c_int {
10434        unsafe { ffi::rocksdb_compactoptions_get_target_level(self.inner) }
10435    }
10436
10437    /// Returns the current `target_path_id` setting.
10438    ///
10439    /// See [`Self::set_target_path_id`] for what this controls.
10440    pub fn get_target_path_id(&self) -> c_int {
10441        unsafe { ffi::rocksdb_compactoptions_get_target_path_id(self.inner) }
10442    }
10443
10444    /// If true, the flush would proceed immediately even it means writes will stall for the
10445    /// duration of the flush; if false the operation will wait until it's possible to do
10446    /// flush w/o causing stall or until required flush is performed by someone else
10447    /// (foreground call or background thread). Default: false.
10448    pub fn set_allow_write_stall(&mut self, val: bool) {
10449        unsafe {
10450            ffi::rocksdb_compactoptions_set_allow_write_stall(self.inner, c_uchar::from(val));
10451        }
10452    }
10453
10454    /// This value represents the maximum number of threads that will concurrently perform a
10455    /// compaction job by breaking it into multiple, smaller ones that are run simultaneously.
10456    /// Default: 1 (i.e. no subcompactions)
10457    ///
10458    /// Dynamically changeable through SetDBOptions() API.
10459    pub fn set_max_subcompactions(&mut self, val: c_int) {
10460        unsafe {
10461            ffi::rocksdb_compactoptions_set_max_subcompactions(self.inner, val);
10462        }
10463    }
10464
10465    /// Compaction outputs will be placed in options.db_paths\[target_path_id\]. Behavior is
10466    /// undefined if target_path_id is out of range.
10467    pub fn set_target_path_id(&mut self, val: c_int) {
10468        unsafe {
10469            ffi::rocksdb_compactoptions_set_target_path_id(self.inner, val);
10470        }
10471    }
10472}
10473
10474pub struct WaitForCompactOptions {
10475    pub(crate) inner: *mut ffi::rocksdb_wait_for_compact_options_t,
10476}
10477
10478impl Default for WaitForCompactOptions {
10479    fn default() -> Self {
10480        let opts = unsafe { ffi::rocksdb_wait_for_compact_options_create() };
10481        assert!(
10482            !opts.is_null(),
10483            "Could not create RocksDB Wait For Compact Options"
10484        );
10485
10486        Self { inner: opts }
10487    }
10488}
10489
10490impl Drop for WaitForCompactOptions {
10491    fn drop(&mut self) {
10492        unsafe {
10493            ffi::rocksdb_wait_for_compact_options_destroy(self.inner);
10494        }
10495    }
10496}
10497
10498impl WaitForCompactOptions {
10499    /// If true, abort waiting if background jobs are paused. If false,
10500    /// ContinueBackgroundWork() must be called to resume the background jobs.
10501    /// Otherwise, jobs that were queued, but not scheduled yet may never finish
10502    /// and WaitForCompact() may wait indefinitely (if timeout is set, it will
10503    /// abort after the timeout).
10504    ///
10505    /// Default: false
10506    pub fn set_abort_on_pause(&mut self, v: bool) {
10507        unsafe {
10508            ffi::rocksdb_wait_for_compact_options_set_abort_on_pause(self.inner, c_uchar::from(v));
10509        }
10510    }
10511
10512    /// If true, flush all column families before starting to wait.
10513    ///
10514    /// Default: false
10515    pub fn set_flush(&mut self, v: bool) {
10516        unsafe {
10517            ffi::rocksdb_wait_for_compact_options_set_flush(self.inner, c_uchar::from(v));
10518        }
10519    }
10520
10521    /// Timeout in microseconds for waiting for compaction to complete.
10522    /// when timeout == 0, WaitForCompact() will wait as long as there's background
10523    /// work to finish.
10524    ///
10525    /// Default: 0
10526    pub fn set_timeout(&mut self, microseconds: u64) {
10527        unsafe {
10528            ffi::rocksdb_wait_for_compact_options_set_timeout(self.inner, microseconds);
10529        }
10530    }
10531
10532    /// A boolean to wait for purge to complete
10533    pub fn set_wait_for_purge(&mut self, val: bool) {
10534        unsafe {
10535            ffi::rocksdb_wait_for_compact_options_set_wait_for_purge(
10536                self.inner,
10537                c_uchar::from(val),
10538            );
10539        }
10540    }
10541
10542    /// Returns the value of the `wait_for_purge` option.
10543    pub fn get_wait_for_purge(&self) -> bool {
10544        unsafe { ffi::rocksdb_wait_for_compact_options_get_wait_for_purge(self.inner) != 0 }
10545    }
10546
10547    /// Returns the current `abort_on_pause` setting.
10548    ///
10549    /// See [`Self::set_abort_on_pause`] for what this controls.
10550    pub fn get_abort_on_pause(&self) -> bool {
10551        unsafe { ffi::rocksdb_wait_for_compact_options_get_abort_on_pause(self.inner) != 0 }
10552    }
10553
10554    /// Returns the current `close_db` setting.
10555    ///
10556    /// See [`Self::set_close_db`] for what this controls.
10557    pub fn get_close_db(&self) -> bool {
10558        unsafe { ffi::rocksdb_wait_for_compact_options_get_close_db(self.inner) != 0 }
10559    }
10560
10561    /// Returns the current `flush` setting.
10562    ///
10563    /// See [`Self::set_flush`] for what this controls.
10564    pub fn get_flush(&self) -> bool {
10565        unsafe { ffi::rocksdb_wait_for_compact_options_get_flush(self.inner) != 0 }
10566    }
10567
10568    /// Returns the current `timeout` setting.
10569    ///
10570    /// See [`Self::set_timeout`] for what this controls.
10571    pub fn get_timeout(&self) -> u64 {
10572        unsafe { ffi::rocksdb_wait_for_compact_options_get_timeout(self.inner) }
10573    }
10574
10575    /// A boolean to call Close() after waiting is done. By the time Close() is called here,
10576    /// there should be no background jobs in progress and no new background jobs should be
10577    /// added. DB may not have been closed if Close() returned Aborted status due to
10578    /// unreleased snapshots in the system. See comments in DB::Close() for details.
10579    pub fn set_close_db(&mut self, val: bool) {
10580        unsafe {
10581            ffi::rocksdb_wait_for_compact_options_set_close_db(self.inner, c_uchar::from(val));
10582        }
10583    }
10584}
10585
10586/// Represents a path where sst files can be put into
10587pub struct DBPath {
10588    pub(crate) inner: *mut ffi::rocksdb_dbpath_t,
10589}
10590
10591impl DBPath {
10592    /// Create a new path
10593    pub fn new<P: AsRef<Path>>(path: P, target_size: u64) -> Result<Self, Error> {
10594        let p = to_cpath(path.as_ref()).unwrap();
10595        let dbpath = unsafe { ffi::rocksdb_dbpath_create(p.as_ptr(), target_size) };
10596        if dbpath.is_null() {
10597            Err(Error::new(format!(
10598                "Could not create path for storing sst files at location: {}",
10599                path.as_ref().display()
10600            )))
10601        } else {
10602            Ok(DBPath { inner: dbpath })
10603        }
10604    }
10605}
10606
10607impl Drop for DBPath {
10608    fn drop(&mut self) {
10609        unsafe {
10610            ffi::rocksdb_dbpath_destroy(self.inner);
10611        }
10612    }
10613}
10614
10615pub struct InfoLogger {
10616    pub(crate) inner: *mut ffi::rocksdb_logger_t,
10617    callback: Option<Arc<LoggerCallback>>,
10618}
10619
10620impl InfoLogger {
10621    /// Creates a new logger that redirects logs to `STDERR` with an optional
10622    /// prefix.
10623    pub fn new_stderr_logger<S: AsRef<str>>(log_level: LogLevel, prefix: Option<S>) -> Self {
10624        let prefix = prefix.map(|s| {
10625            s.as_ref()
10626                .into_c_string()
10627                .expect("cannot have NULL in prefix")
10628        });
10629        let prefix_ptr = match prefix.as_ref() {
10630            Some(s) => s.as_ptr(),
10631            None => std::ptr::null(),
10632        };
10633        let inner =
10634            unsafe { ffi::rocksdb_logger_create_stderr_logger(log_level as i32, prefix_ptr) };
10635        Self {
10636            inner,
10637            // no Rust callback: RocksDB implements this
10638            callback: None,
10639        }
10640    }
10641
10642    /// Creates a new logger that redirects logs to a custom callback.
10643    pub fn new_callback_logger<F: Fn(LogLevel, &str) + Sync + Send + 'static>(
10644        level: LogLevel,
10645        cb: F,
10646    ) -> Self {
10647        // use an Arc<Box<...>> so we can reference count, and still pass a thin pointer to C
10648        let arc_cb: Arc<LoggerCallback> = Arc::new(Box::new(cb));
10649        let raw_cb: LoggerCallbackPtr = Arc::as_ptr(&arc_cb);
10650        let inner = unsafe {
10651            ffi::rocksdb_logger_create_callback_logger(
10652                level as i32,
10653                Some(logger_callback),
10654                raw_cb as *mut c_void,
10655            )
10656        };
10657        Self {
10658            inner,
10659            callback: Some(arc_cb),
10660        }
10661    }
10662}
10663
10664impl Drop for InfoLogger {
10665    fn drop(&mut self) {
10666        unsafe {
10667            ffi::rocksdb_logger_destroy(self.inner);
10668        }
10669    }
10670}
10671
10672/// Options for importing column families. See
10673/// [DB::create_column_family_with_import](crate::DB::create_column_family_with_import).
10674pub struct ImportColumnFamilyOptions {
10675    pub(crate) inner: *mut ffi::rocksdb_import_column_family_options_t,
10676}
10677
10678impl ImportColumnFamilyOptions {
10679    pub fn new() -> Self {
10680        let inner = unsafe { ffi::rocksdb_import_column_family_options_create() };
10681        ImportColumnFamilyOptions { inner }
10682    }
10683
10684    /// Determines whether to move the provided set of files on import. The default
10685    /// behavior is to copy the external files on import. Setting `move_files` to `true`
10686    /// will move the files instead of copying them. See
10687    /// [DB::create_column_family_with_import](crate::DB::create_column_family_with_import)
10688    /// for more information.
10689    pub fn set_move_files(&mut self, move_files: bool) {
10690        unsafe {
10691            ffi::rocksdb_import_column_family_options_set_move_files(
10692                self.inner,
10693                c_uchar::from(move_files),
10694            );
10695        }
10696    }
10697
10698    /// Returns the current `move_files` setting.
10699    ///
10700    /// See [`Self::set_move_files`] for what this controls.
10701    pub fn get_move_files(&self) -> bool {
10702        unsafe { ffi::rocksdb_import_column_family_options_get_move_files(self.inner) != 0 }
10703    }
10704}
10705
10706impl Default for ImportColumnFamilyOptions {
10707    fn default() -> Self {
10708        Self::new()
10709    }
10710}
10711
10712impl Drop for ImportColumnFamilyOptions {
10713    fn drop(&mut self) {
10714        unsafe { ffi::rocksdb_import_column_family_options_destroy(self.inner) }
10715    }
10716}
10717
10718/// Ensures the unsafe casts use the same type.
10719type LoggerCallbackPtr = *const LoggerCallback;
10720
10721/// The closure behind [`ReadOptions::set_table_filter`], boxed twice so the `state` handed to
10722/// the C API is a thin pointer.
10723type TableFilterCallback = Box<dyn Fn(&TableProperties<'_>) -> bool + Send + Sync>;
10724
10725/// Reclaims the box installed by [`ReadOptions::set_table_filter`].
10726///
10727/// RocksDB calls this exactly once per filter, from `ClearTableFilter`, which runs when a new
10728/// filter replaces this one, when the filter is cleared, and when the read options are
10729/// destroyed.
10730unsafe extern "C" fn table_filter_destructor(state: *mut c_void) {
10731    drop(unsafe { Box::from_raw(state.cast::<TableFilterCallback>()) });
10732}
10733
10734unsafe extern "C" fn table_filter_callback(
10735    state: *mut c_void,
10736    table_properties: *const ffi::rocksdb_table_properties_t,
10737) -> c_uchar {
10738    // Shared reference, not `&mut`: several iterator threads can hold the same `ReadOptions`.
10739    let filter = unsafe { &*state.cast::<TableFilterCallback>() };
10740    // RocksDB passes a reference to a `TableProperties` that only lives for this call, and
10741    // the `Fn(&TableProperties<'_>)` bound is higher ranked, so the borrow cannot escape.
10742    let properties = unsafe { TableProperties::from_ptr(table_properties) };
10743    c_uchar::from(filter(&properties))
10744}
10745
10746unsafe extern "C" fn logger_callback(
10747    raw_cb: *mut c_void,
10748    level: c_uint,
10749    msg: *mut c_char,
10750    len: size_t,
10751) {
10752    let rust_callback: &LoggerCallback = unsafe { &*(raw_cb as LoggerCallbackPtr) };
10753    let raw_msg = if len == 0 {
10754        &[][..]
10755    } else {
10756        unsafe { std::slice::from_raw_parts(msg.cast_const().cast::<u8>(), len) }
10757    };
10758    let msg = String::from_utf8_lossy(raw_msg);
10759    // Don't panic on an unexpected level: this runs in an `extern "C"` frame,
10760    // where unwinding aborts the process. Losing the exact level of one log
10761    // line is not worth taking the process down for.
10762    let level = LogLevel::try_from_raw(level as i32).unwrap_or(LogLevel::Info);
10763    (rust_callback)(level, &msg);
10764}
10765
10766#[cfg(test)]
10767mod tests {
10768    use crate::cache::Cache;
10769    use crate::db_options::{DBCompactionPri, InfoLogger, WriteBufferManager};
10770    use crate::{MemtableFactory, Options};
10771
10772    /// `set_prefix_range_in_place` is an allocation-free reimplementation of
10773    /// `set_iterate_range(PrefixRange(..))`. It has to produce byte-identical
10774    /// bounds, including for the awkward cases: empty prefixes, trailing 0xff
10775    /// bytes, and all-0xff prefixes (which have no successor).
10776    #[test]
10777    fn prefix_range_in_place_matches_prefix_range() {
10778        let cases: &[&[u8]] = &[
10779            b"",
10780            b"a",
10781            b"foo",
10782            b"\x00",
10783            b"\xff",
10784            b"\xff\xff",
10785            b"a\xff",
10786            b"a\xff\xff",
10787            b"\xfe\xff",
10788            b"prefix\x00\xff",
10789        ];
10790
10791        for prefix in cases {
10792            let mut expected = crate::ReadOptions::default();
10793            expected.set_iterate_range(crate::PrefixRange(*prefix));
10794
10795            let mut actual = crate::ReadOptions::default();
10796            actual.set_prefix_range_in_place(prefix);
10797
10798            assert_eq!(
10799                actual.iterate_lower_bound, expected.iterate_lower_bound,
10800                "lower bound mismatch for prefix {prefix:?}"
10801            );
10802            assert_eq!(
10803                actual.iterate_upper_bound, expected.iterate_upper_bound,
10804                "upper bound mismatch for prefix {prefix:?}"
10805            );
10806        }
10807    }
10808
10809    /// The whole point of the in-place setter is that a reused `ReadOptions`
10810    /// stops reallocating, so overwriting the bounds repeatedly must keep the
10811    /// results correct rather than leaving stale bytes behind.
10812    #[test]
10813    fn prefix_range_in_place_is_reusable() {
10814        let mut opts = crate::ReadOptions::default();
10815
10816        opts.set_prefix_range_in_place(b"aaaa");
10817        assert_eq!(opts.iterate_lower_bound.as_deref(), Some(&b"aaaa"[..]));
10818        assert_eq!(opts.iterate_upper_bound.as_deref(), Some(&b"aaab"[..]));
10819
10820        // Shorter prefix must truncate, not leave the tail of the previous one.
10821        opts.set_prefix_range_in_place(b"b");
10822        assert_eq!(opts.iterate_lower_bound.as_deref(), Some(&b"b"[..]));
10823        assert_eq!(opts.iterate_upper_bound.as_deref(), Some(&b"c"[..]));
10824
10825        // An all-0xff prefix has no successor: the upper bound must be cleared.
10826        opts.set_prefix_range_in_place(b"\xff");
10827        assert_eq!(opts.iterate_lower_bound.as_deref(), Some(&b"\xff"[..]));
10828        assert_eq!(opts.iterate_upper_bound, None);
10829
10830        // An empty prefix is the full range: both bounds cleared.
10831        opts.set_prefix_range_in_place(b"");
10832        assert_eq!(opts.iterate_lower_bound, None);
10833        assert_eq!(opts.iterate_upper_bound, None);
10834    }
10835
10836    #[test]
10837    fn test_enable_statistics() {
10838        let mut opts = Options::default();
10839        assert_eq!(None, opts.get_statistics());
10840        opts.enable_statistics();
10841        opts.set_stats_dump_period_sec(60);
10842        assert!(opts.get_statistics().is_some());
10843
10844        let opts = Options::default();
10845        assert!(opts.get_statistics().is_none());
10846    }
10847
10848    #[test]
10849    fn test_set_memtable_factory() {
10850        let mut opts = Options::default();
10851        opts.set_memtable_factory(MemtableFactory::Vector);
10852        opts.set_memtable_factory(MemtableFactory::HashLinkList { bucket_count: 100 });
10853        opts.set_memtable_factory(MemtableFactory::HashSkipList {
10854            bucket_count: 100,
10855            height: 4,
10856            branching_factor: 4,
10857        });
10858    }
10859
10860    #[test]
10861    fn test_use_fsync() {
10862        let mut opts = Options::default();
10863        assert!(!opts.get_use_fsync());
10864        opts.set_use_fsync(true);
10865        assert!(opts.get_use_fsync());
10866    }
10867
10868    #[test]
10869    fn test_set_stats_persist_period_sec() {
10870        let mut opts = Options::default();
10871        opts.enable_statistics();
10872        opts.set_stats_persist_period_sec(5);
10873        assert!(opts.get_statistics().is_some());
10874
10875        let opts = Options::default();
10876        assert!(opts.get_statistics().is_none());
10877    }
10878
10879    #[test]
10880    fn test_set_write_buffer_manager() {
10881        let mut opts = Options::default();
10882        let lrucache = Cache::new_lru_cache(100);
10883        let write_buffer_manager =
10884            WriteBufferManager::new_write_buffer_manager_with_cache(100, false, lrucache);
10885        assert_eq!(write_buffer_manager.get_buffer_size(), 100);
10886        assert_eq!(write_buffer_manager.get_usage(), 0);
10887        assert!(write_buffer_manager.enabled());
10888
10889        opts.set_write_buffer_manager(&write_buffer_manager);
10890        drop(opts);
10891
10892        // WriteBufferManager outlives options
10893        assert!(write_buffer_manager.enabled());
10894    }
10895
10896    #[test]
10897    fn compaction_pri() {
10898        let mut opts = Options::default();
10899        opts.set_compaction_pri(DBCompactionPri::RoundRobin);
10900        opts.create_if_missing(true);
10901        let tmp = tempfile::tempdir().unwrap();
10902        let _db = crate::DB::open(&opts, tmp.path()).unwrap();
10903
10904        let options = std::fs::read_dir(tmp.path())
10905            .unwrap()
10906            .find_map(|x| {
10907                let x = x.ok()?;
10908                x.file_name()
10909                    .into_string()
10910                    .unwrap()
10911                    .contains("OPTIONS")
10912                    .then_some(x.path())
10913            })
10914            .map(std::fs::read_to_string)
10915            .unwrap()
10916            .unwrap();
10917
10918        assert!(options.contains("compaction_pri=kRoundRobin"));
10919    }
10920
10921    #[test]
10922    fn test_callback_logger() {
10923        let (log_snd, log_rcv) = std::sync::mpsc::channel();
10924        let callback = move |level, msg: &str| {
10925            log_snd.send((level, msg.to_string())).ok();
10926        };
10927
10928        let mut opts = Options::default();
10929        opts.create_if_missing(true);
10930        opts.set_info_logger(InfoLogger::new_callback_logger(
10931            super::LogLevel::Debug,
10932            callback,
10933        ));
10934
10935        // create 2 DBs with the options then drop the options to ensure it is reference counted
10936        let tmp = tempfile::tempdir().unwrap();
10937        let db = crate::DB::open(&opts, tmp.path()).unwrap();
10938        db.put(b"testkey", b"testvalue").unwrap();
10939        db.flush().unwrap();
10940        db.delete(b"testkey").unwrap();
10941        db.flush().unwrap();
10942        db.compact_range(Some(b"a"), Some(b"z"));
10943        assert!(log_rcv.try_recv().is_ok());
10944        drop(db);
10945
10946        let tmp2 = tempfile::tempdir().unwrap();
10947        let db2 = crate::DB::open(&opts, tmp2.path()).unwrap();
10948
10949        // get the configured logger before dropping the options
10950        let logger = opts.get_info_logger();
10951        drop(opts);
10952
10953        // clear the logs and make sure the callback is called by db2
10954        while log_rcv.try_recv().is_ok() {}
10955        assert!(log_rcv.try_recv().is_err());
10956
10957        db2.put(b"testkey2", b"testvalue2").unwrap();
10958        db2.flush().unwrap();
10959        db2.delete(b"testkey2").unwrap();
10960        db2.flush().unwrap();
10961        db2.compact_range(Some(b"a"), Some(b"z"));
10962
10963        drop(db2);
10964        assert!(log_rcv.try_recv().is_ok());
10965
10966        // clear the logs
10967        while log_rcv.try_recv().is_ok() {}
10968        assert!(log_rcv.try_recv().is_err());
10969
10970        // create a db with the copied logger to check lifetimes
10971        let tmp3 = tempfile::tempdir().unwrap();
10972        let mut opts2 = Options::default();
10973        opts2.create_if_missing(true);
10974        opts2.set_info_logger(logger);
10975        let db3 = crate::DB::open(&opts2, tmp3.path()).unwrap();
10976        drop(opts2);
10977        db3.put(b"testkey3", b"testvalue3").unwrap();
10978        db3.flush().unwrap();
10979        db3.delete(b"testkey3").unwrap();
10980        db3.flush().unwrap();
10981        db3.compact_range(Some(b"a"), Some(b"z"));
10982        assert!(log_rcv.try_recv().is_ok());
10983        drop(db3);
10984    }
10985}