Skip to main content

rust_rocksdb/
env_options.rs

1//! Per-file I/O settings for the APIs that open a file outside of a DB.
2//!
3//! [`EnvOptions`] is RocksDB's `EnvOptions`. A DB derives one for every file
4//! it opens from its own [`Options`](crate::Options), so most applications
5//! never build one by hand. It matters for the APIs that open a file with no
6//! `Options` to derive from, such as [`SstFileWriter`](crate::SstFileWriter)
7//! and the trace readers and writers.
8
9use libc::c_uchar;
10
11use crate::ffi;
12
13/// Per-file I/O settings handed to an [`Env`](crate::Env) when it opens a file.
14///
15/// A fresh instance carries the values a default `DBOptions` would produce.
16/// Each setter below names the default it starts from.
17///
18/// See `rocksdb/include/rocksdb/env.h`.
19pub struct EnvOptions {
20    pub(crate) inner: *mut ffi::rocksdb_envoptions_t,
21}
22
23// Safety note matches the other options types in `db_options.rs`: the inner
24// pointer is never aliased, and RocksDB keeps no thread-local state for
25// `EnvOptions`. Every mutation goes through `&mut self`, so there is no
26// interior mutability for `Sync` to worry about.
27unsafe impl Send for EnvOptions {}
28unsafe impl Sync for EnvOptions {}
29
30impl Default for EnvOptions {
31    fn default() -> Self {
32        let inner = unsafe { ffi::rocksdb_envoptions_create() };
33        assert!(!inner.is_null(), "Could not create RocksDB env options");
34
35        Self { inner }
36    }
37}
38
39impl Drop for EnvOptions {
40    fn drop(&mut self) {
41        unsafe {
42            ffi::rocksdb_envoptions_destroy(self.inner);
43        }
44    }
45}
46
47impl EnvOptions {
48    /// Returns the raw pointer the C API reads these options through.
49    pub(crate) fn as_ptr(&self) -> *const ffi::rocksdb_envoptions_t {
50        self.inner
51    }
52
53    /// If true, reads go through `mmap` instead of `read`.
54    ///
55    /// Not recommended on a 32-bit OS, where address space runs out well
56    /// before the data does.
57    ///
58    /// The POSIX file system ignores
59    /// [`set_use_direct_reads`](Self::set_use_direct_reads) while this is on.
60    ///
61    /// Default: false
62    pub fn set_use_mmap_reads(&mut self, v: bool) {
63        unsafe {
64            ffi::rocksdb_envoptions_set_use_mmap_reads(self.inner, c_uchar::from(v));
65        }
66    }
67
68    /// Returns the current `use_mmap_reads` setting.
69    ///
70    /// See [`Self::set_use_mmap_reads`] for what this controls.
71    pub fn get_use_mmap_reads(&self) -> bool {
72        unsafe { ffi::rocksdb_envoptions_get_use_mmap_reads(self.inner) != 0 }
73    }
74
75    /// If true, writes go through `mmap` instead of `write`.
76    ///
77    /// The POSIX file system ignores
78    /// [`set_use_direct_writes`](Self::set_use_direct_writes) while this is on.
79    ///
80    /// Default: false
81    pub fn set_use_mmap_writes(&mut self, v: bool) {
82        unsafe {
83            ffi::rocksdb_envoptions_set_use_mmap_writes(self.inner, c_uchar::from(v));
84        }
85    }
86
87    /// Returns the current `use_mmap_writes` setting.
88    ///
89    /// See [`Self::set_use_mmap_writes`] for what this controls.
90    pub fn get_use_mmap_writes(&self) -> bool {
91        unsafe { ffi::rocksdb_envoptions_get_use_mmap_writes(self.inner) != 0 }
92    }
93
94    /// If true, read this file with direct I/O, bypassing the page cache.
95    ///
96    /// This is the file-level flag, not [`Options::set_use_direct_reads`].
97    /// The DB option decides what RocksDB puts into the `EnvOptions` it builds
98    /// for its own files. This one applies to whatever the caller opens with
99    /// these options, and nothing propagates between the two.
100    ///
101    /// On POSIX, Linux and friends pass `O_DIRECT` at open time while macOS
102    /// sets `F_NOCACHE` on the descriptor instead. Either way the flag is
103    /// ignored while [`set_use_mmap_reads`](Self::set_use_mmap_reads) is on.
104    ///
105    /// Default: false
106    ///
107    /// [`Options::set_use_direct_reads`]: crate::Options::set_use_direct_reads
108    pub fn set_use_direct_reads(&mut self, v: bool) {
109        unsafe {
110            ffi::rocksdb_envoptions_set_use_direct_reads(self.inner, c_uchar::from(v));
111        }
112    }
113
114    /// Returns the current `use_direct_reads` setting.
115    ///
116    /// See [`Self::set_use_direct_reads`] for what this controls.
117    pub fn get_use_direct_reads(&self) -> bool {
118        unsafe { ffi::rocksdb_envoptions_get_use_direct_reads(self.inner) != 0 }
119    }
120
121    /// If true, write this file with direct I/O, bypassing the page cache.
122    ///
123    /// This is the file-level flag, not
124    /// [`Options::set_use_direct_io_for_flush_and_compaction`]. The DB option
125    /// decides what RocksDB puts into the `EnvOptions` it builds for its own
126    /// files. This one applies to whatever the caller opens with these
127    /// options, and nothing propagates between the two.
128    ///
129    /// On POSIX, Linux and friends pass `O_DIRECT` at open time while macOS
130    /// sets `F_NOCACHE` on the descriptor instead. Either way the flag is
131    /// ignored while [`set_use_mmap_writes`](Self::set_use_mmap_writes) is on.
132    ///
133    /// Default: false
134    ///
135    /// [`Options::set_use_direct_io_for_flush_and_compaction`]: crate::Options::set_use_direct_io_for_flush_and_compaction
136    pub fn set_use_direct_writes(&mut self, v: bool) {
137        unsafe {
138            ffi::rocksdb_envoptions_set_use_direct_writes(self.inner, c_uchar::from(v));
139        }
140    }
141
142    /// Returns the current `use_direct_writes` setting.
143    ///
144    /// See [`Self::set_use_direct_writes`] for what this controls.
145    pub fn get_use_direct_writes(&self) -> bool {
146        unsafe { ffi::rocksdb_envoptions_get_use_direct_writes(self.inner) != 0 }
147    }
148
149    /// If false, RocksDB skips the `fallocate` calls it would otherwise make
150    /// to preallocate space for a file.
151    ///
152    /// Linux only. Builds without `fallocate` compile the calls out, so the
153    /// setting has no effect there.
154    ///
155    /// Default: true
156    pub fn set_allow_fallocate(&mut self, v: bool) {
157        unsafe {
158            ffi::rocksdb_envoptions_set_allow_fallocate(self.inner, c_uchar::from(v));
159        }
160    }
161
162    /// Returns the current `allow_fallocate` setting.
163    ///
164    /// See [`Self::set_allow_fallocate`] for what this controls.
165    pub fn get_allow_fallocate(&self) -> bool {
166        unsafe { ffi::rocksdb_envoptions_get_allow_fallocate(self.inner) != 0 }
167    }
168
169    /// If true, opened descriptors get `FD_CLOEXEC` so they are not inherited
170    /// across `exec`.
171    ///
172    /// This maps to `EnvOptions::set_fd_cloexec`. POSIX only, ignored on
173    /// Windows.
174    ///
175    /// Default: true
176    pub fn set_fd_cloexec(&mut self, v: bool) {
177        unsafe {
178            ffi::rocksdb_envoptions_set_fd_cloexec(self.inner, c_uchar::from(v));
179        }
180    }
181
182    /// Returns the current `fd_cloexec` setting.
183    ///
184    /// See [`Self::set_fd_cloexec`] for what this controls.
185    pub fn get_fd_cloexec(&self) -> bool {
186        unsafe { ffi::rocksdb_envoptions_get_fd_cloexec(self.inner) != 0 }
187    }
188
189    /// Asks the OS to write the file back to disk incrementally, one request
190    /// per this many bytes written. 0 turns it off.
191    ///
192    /// This spreads writeback out instead of leaving it all for the final
193    /// sync. It is not a durability guarantee on its own.
194    ///
195    /// Default: 0
196    pub fn set_bytes_per_sync(&mut self, v: u64) {
197        unsafe {
198            ffi::rocksdb_envoptions_set_bytes_per_sync(self.inner, v);
199        }
200    }
201
202    /// Returns the current `bytes_per_sync` setting in bytes.
203    ///
204    /// See [`Self::set_bytes_per_sync`] for what this controls.
205    pub fn get_bytes_per_sync(&self) -> u64 {
206        unsafe { ffi::rocksdb_envoptions_get_bytes_per_sync(self.inner) }
207    }
208
209    /// When true, guarantees at most [`bytes_per_sync`](Self::set_bytes_per_sync)
210    /// bytes are queued for writeback at any moment.
211    ///
212    /// On Linux this waits for the previous `sync_file_range` to finish before
213    /// issuing the next one, so compression and other processing keep running
214    /// in the gap and only I/O falling behind blocks. Everywhere else it falls
215    /// back to a blocking `WritableFile::Sync`, which stops processing and
216    /// I/O from overlapping at all.
217    ///
218    /// This adds no durability guarantee, because `sync_file_range` does not
219    /// write out metadata.
220    ///
221    /// Default: false
222    pub fn set_strict_bytes_per_sync(&mut self, v: bool) {
223        unsafe {
224            ffi::rocksdb_envoptions_set_strict_bytes_per_sync(self.inner, c_uchar::from(v));
225        }
226    }
227
228    /// Returns the current `strict_bytes_per_sync` setting.
229    ///
230    /// See [`Self::set_strict_bytes_per_sync`] for what this controls.
231    pub fn get_strict_bytes_per_sync(&self) -> bool {
232        unsafe { ffi::rocksdb_envoptions_get_strict_bytes_per_sync(self.inner) != 0 }
233    }
234
235    /// If true, preallocation passes `FALLOC_FL_KEEP_SIZE`, so the reported
236    /// file size does not grow with the preallocated space. If false,
237    /// preallocation grows the file size too, which is faster for workloads
238    /// that sync on every write.
239    ///
240    /// Linux only, and only when [`allow_fallocate`](Self::set_allow_fallocate)
241    /// is on. RocksDB itself uses true for MANIFEST writes and false for WAL
242    /// writes.
243    ///
244    /// Default: true
245    pub fn set_fallocate_with_keep_size(&mut self, v: bool) {
246        unsafe {
247            ffi::rocksdb_envoptions_set_fallocate_with_keep_size(self.inner, c_uchar::from(v));
248        }
249    }
250
251    /// Returns the current `fallocate_with_keep_size` setting.
252    ///
253    /// See [`Self::set_fallocate_with_keep_size`] for what this controls.
254    pub fn get_fallocate_with_keep_size(&self) -> bool {
255        unsafe { ffi::rocksdb_envoptions_get_fallocate_with_keep_size(self.inner) != 0 }
256    }
257
258    /// If non-zero, compaction reads this many bytes at a time. On spinning
259    /// disks this turns compaction's random reads into sequential ones.
260    ///
261    /// Default: 2 MiB
262    pub fn set_compaction_readahead_size(&mut self, v: usize) {
263        unsafe {
264            ffi::rocksdb_envoptions_set_compaction_readahead_size(self.inner, v);
265        }
266    }
267
268    /// Returns the current `compaction_readahead_size` setting in bytes.
269    ///
270    /// See [`Self::set_compaction_readahead_size`] for what this controls.
271    pub fn get_compaction_readahead_size(&self) -> usize {
272        unsafe { ffi::rocksdb_envoptions_get_compaction_readahead_size(self.inner) }
273    }
274
275    /// Caps the buffer `WritableFileWriter` uses.
276    ///
277    /// With buffered I/O the buffer grows up to this limit. With direct I/O it
278    /// is fixed at this size, so that write requests stay aligned even when
279    /// the logical sector size is unusual.
280    ///
281    /// Default: 1 MiB
282    pub fn set_writable_file_max_buffer_size(&mut self, v: usize) {
283        unsafe {
284            ffi::rocksdb_envoptions_set_writable_file_max_buffer_size(self.inner, v);
285        }
286    }
287
288    /// Returns the current `writable_file_max_buffer_size` setting in bytes.
289    ///
290    /// See [`Self::set_writable_file_max_buffer_size`] for what this controls.
291    pub fn get_writable_file_max_buffer_size(&self) -> usize {
292        unsafe { ffi::rocksdb_envoptions_get_writable_file_max_buffer_size(self.inner) }
293    }
294
295    /// Rate limits writes to files opened with these options.
296    ///
297    /// The arguments match [`Options::set_ratelimiter`], and so does the
298    /// handling: the C API's `rocksdb_ratelimiter_t` is only a handle around a
299    /// `shared_ptr<RateLimiter>`, and `rocksdb_envoptions_set_rate_limiter`
300    /// copies that `shared_ptr` into the options object (see
301    /// `rocksdb_envoptions_t::rate_limiter` in `db/c.cc`). The limiter stays
302    /// alive as long as these options do, so the handle is destroyed right
303    /// after the call.
304    ///
305    /// There is no getter and no way to clear this. The C API exposes only the
306    /// setter.
307    ///
308    /// Default: no limit
309    ///
310    /// [`Options::set_ratelimiter`]: crate::Options::set_ratelimiter
311    pub fn set_ratelimiter(
312        &mut self,
313        rate_bytes_per_sec: i64,
314        refill_period_us: i64,
315        fairness: i32,
316    ) {
317        unsafe {
318            let ratelimiter =
319                ffi::rocksdb_ratelimiter_create(rate_bytes_per_sec, refill_period_us, fairness);
320            ffi::rocksdb_envoptions_set_rate_limiter(self.inner, ratelimiter);
321            ffi::rocksdb_ratelimiter_destroy(ratelimiter);
322        }
323    }
324}