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