raindb/options.rs
1// Copyright (c) 2021 Google LLC
2//
3// Use of this source code is governed by an MIT-style
4// license that can be found in the LICENSE file or at
5// https://opensource.org/licenses/MIT.
6
7/*!
8This module holds the various option structures that can be passed to RainDB operations
9*/
10
11use std::sync::Arc;
12
13use crate::filter_policy::{BloomFilterPolicy, FilterPolicy};
14use crate::fs::{FileSystem, InMemoryFileSystem, OsFileSystem};
15use crate::tables::block::DataBlockReader;
16use crate::tables::BlockCacheKey;
17use crate::utils::cache::LRUCache;
18use crate::{Cache, Snapshot};
19
20/**
21Holds options to control database behavior.
22
23There is a mix of options to configure here that are remniscent of those configurable in
24LevelDB and RocksDB.
25*/
26#[derive(Clone, Debug)]
27pub struct DbOptions {
28 // TODO: Add option for users to set a custom comparator.
29 /**
30 The path of the director to use for the database's operations.
31
32 **This defaults to the current working directory.**
33 */
34 pub db_path: String,
35
36 /**
37 The maximum size that the memtable can reach before it is flushed to disk.
38
39 Up to two memtables can reside in memory at a time, one actively serving reads and writes
40 and a second one in the process of being flushed to disk.
41
42 This option corresponds to `write_buffer_size` in LevelDB. We feel the RainDB name is more clear
43 as to what function this option performs.
44
45 **This defaults to 4 MiB.**
46 */
47 pub max_memtable_size: usize,
48
49 /**
50 This amount of bytes will be written to a file before switching to a new one.
51
52 Most clients should leave this parameter alone. However if your filesystem is more efficient
53 with larger files, you could consider increasing the value. The downside will be longer
54 compactions and hence longer latency/performance hiccups. Another reason to increase this
55 parameter might be when you are initially populating a large database.
56
57 **This defaults to 2 MiB.**
58 */
59 pub max_file_size: u64,
60
61 /**
62 The approximate maximum size of user data that is allowed to be packed into a block of a table
63 file.
64
65 The data considered here is uncompressed data. The actual size of the data on disk may be smaller
66 due to compression.
67
68 In LevelDB this is configurable and has a default size of 4 KiB.
69 */
70 pub max_block_size: usize,
71
72 /**
73 A wrapper around a particular file system to use.
74
75 **This defaults to [`OsFileSystem`](crate::fs::OsFileSystem).**
76 */
77 pub filesystem_provider: Arc<dyn FileSystem>,
78
79 /**
80 The filter policy to use for filtering requests to table files to reduce disk seeks.
81
82 **This defaults to [`BloomFilterPolicy`](crate::filter_policy::BloomFilterPolicy).**
83 */
84 pub filter_policy: Arc<dyn FilterPolicy>,
85
86 /**
87 Cache used to store blocks read from disk in-memory to save on disk reads.
88
89 This cache store uncompressed data so--if changed--the cache size should be appropriate to the
90 application using the database.
91
92 **This defaults to an 8 MiB internal cache if not set.**
93 */
94 pub block_cache: Arc<dyn Cache<BlockCacheKey, Arc<DataBlockReader>>>,
95
96 /// If true, the database will be created if it is missing.
97 pub create_if_missing: bool,
98
99 /// If true, an error is raised if the database already exists.
100 pub error_if_exists: bool,
101
102 /**
103 If true, append to existing manifest and write-ahead logs when opening a database.
104
105 **This defaults to true (unlike in LevelDB that defaults to false).**
106 */
107 pub reuse_log_files: bool,
108}
109
110/// Public methods
111impl DbOptions {
112 /// Get [`DbOptions`] with an in-memory file system.
113 pub fn with_memory_env() -> DbOptions {
114 DbOptions {
115 filesystem_provider: Arc::new(InMemoryFileSystem::new()),
116 ..DbOptions::default()
117 }
118 }
119
120 /// Get the database path.
121 pub fn db_path(&self) -> &str {
122 self.db_path.as_str()
123 }
124
125 /// Get the write buffer size.
126 pub fn max_memtable_size(&self) -> usize {
127 self.max_memtable_size
128 }
129
130 /// Get the database's maximum table file size.
131 pub fn max_file_size(&self) -> u64 {
132 self.max_file_size
133 }
134
135 /// Get the maximum block size.
136 pub fn max_block_size(&self) -> usize {
137 self.max_block_size
138 }
139
140 /// Get the whether the database is reusing log files.
141 pub fn reuse_log_files(&self) -> bool {
142 self.reuse_log_files
143 }
144
145 /// Get a strong reference to the file system provider.
146 pub fn filesystem_provider(&self) -> Arc<dyn FileSystem> {
147 Arc::clone(&self.filesystem_provider)
148 }
149
150 /// Get a strong reference to the filter policy.
151 pub fn filter_policy(&self) -> Arc<dyn FilterPolicy> {
152 Arc::clone(&self.filter_policy)
153 }
154
155 /// Get a strong reference to the block cache.
156 pub fn block_cache(&self) -> Arc<dyn Cache<BlockCacheKey, Arc<DataBlockReader>>> {
157 Arc::clone(&self.block_cache)
158 }
159
160 /// Returns true if we should create the database if it is missing.
161 pub fn create_if_missing(&self) -> bool {
162 self.create_if_missing
163 }
164
165 /// Get a reference to the db options's error if exists.
166 pub fn error_if_exists(&self) -> bool {
167 self.error_if_exists
168 }
169}
170
171impl Default for DbOptions {
172 fn default() -> Self {
173 DbOptions {
174 db_path: std::env::current_dir()
175 .unwrap()
176 .to_str()
177 .unwrap()
178 .to_owned(),
179 max_memtable_size: 4 * 1024 * 1024,
180 max_file_size: 2 * 1024 * 1024,
181 max_block_size: 4 * 1024,
182 filesystem_provider: Arc::new(OsFileSystem::new()),
183 filter_policy: Arc::new(BloomFilterPolicy::new(10)),
184 block_cache: Arc::new(LRUCache::<BlockCacheKey, Arc<DataBlockReader>>::new(
185 8 * 1024 * 1024,
186 )),
187 create_if_missing: false,
188 error_if_exists: false,
189 reuse_log_files: true,
190 }
191 }
192}
193
194/// Options for read operations.
195#[derive(Clone, Debug)]
196pub struct ReadOptions {
197 /**
198 Cache data read as a result of a read operation.
199
200 Callers may want to set this to false for bulk scans.
201
202 **Defaults to true.**
203 */
204 pub fill_cache: bool,
205
206 /**
207 Configure the read operation to read as of the state of the supplied snapshot. If [`None`], the
208 read will be performed at the state of the database when the request was received.
209
210 This snapshot must have been received by the database it is being passed to and must not have
211 been released yet.
212 */
213 pub snapshot: Option<Snapshot>,
214}
215
216impl Default for ReadOptions {
217 fn default() -> Self {
218 Self {
219 fill_cache: true,
220 snapshot: None,
221 }
222 }
223}
224
225/// Options for write operations.
226#[derive(Clone, Debug)]
227pub struct WriteOptions {
228 /**
229 Whether or not to perform the write operation synchronously.
230
231 If true, the program will try to ensure that the write is flusehd completely to disk before it
232 considers the write complete. This extra check means that writes with this flag on will be
233 slower.
234
235 If false and the machine crashes, some recent writes might be lost. Note that, if it is just the
236 program that crashes (i.e. the machine does not reboot), then no writes will be lost.
237
238 In other words, writes with this flag `false` has the same semantics as just a `write()` system
239 call. A write with the flag as `true` has the semantics of a `write()` followed by an `fsync()`.
240
241 **Defaults to false.**
242 */
243 pub synchronous: bool,
244}
245
246impl Default for WriteOptions {
247 fn default() -> Self {
248 Self { synchronous: false }
249 }
250}