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}