libmdbx_remote/
flags.rs

1use bitflags::bitflags;
2use ffi::*;
3use serde::{Deserialize, Serialize};
4
5/// MDBX sync mode
6#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
7pub enum SyncMode {
8    /// Default robust and durable sync mode.
9    /// Metadata is written and flushed to disk after a data is written and flushed, which
10    /// guarantees the integrity of the database in the event of a crash at any time.
11    Durable,
12
13    /// Don't sync the meta-page after commit.
14    ///
15    /// Flush system buffers to disk only once per transaction commit, omit the metadata flush.
16    /// Defer that until the system flushes files to disk, or next non-read-only commit or
17    /// [`Environment::sync()`](crate::Environment::sync). Depending on the platform and
18    /// hardware, with [`SyncMode::NoMetaSync`] you may get a doubling of write performance.
19    ///
20    /// This trade-off maintains database integrity, but a system crash may undo the last committed
21    /// transaction. I.e. it preserves the ACPI (atomicity, consistency, isolation) but not D
22    /// (durability) database property.
23    NoMetaSync,
24
25    /// Don't sync anything but keep previous steady commits.
26    ///
27    /// [`SyncMode::UtterlyNoSync`] the [`SyncMode::SafeNoSync`] flag disable similarly flush
28    /// system buffers to disk when committing a transaction. But there is a huge difference in
29    /// how are recycled the MVCC snapshots corresponding to previous "steady" transactions
30    /// (see below).
31    ///
32    /// With [`crate::EnvironmentKind::WriteMap`] the [`SyncMode::SafeNoSync`] instructs MDBX to
33    /// use asynchronous mmap-flushes to disk. Asynchronous mmap-flushes means that actually
34    /// all writes will scheduled and performed by operation system on it own manner, i.e.
35    /// unordered. MDBX itself just notify operating system that it would be nice to write data
36    /// to disk, but no more.
37    ///
38    /// Depending on the platform and hardware, with [`SyncMode::SafeNoSync`] you may get a
39    /// multiple increase of write performance, even 10 times or more.
40    ///
41    /// In contrast to [`SyncMode::UtterlyNoSync`] mode, with [`SyncMode::SafeNoSync`] flag MDBX
42    /// will keeps untouched pages within B-tree of the last transaction "steady" which was
43    /// synced to disk completely. This has big implications for both data durability and
44    /// (unfortunately) performance:
45    /// - A system crash can't corrupt the database, but you will lose the last transactions;
46    ///   because MDBX will rollback to last steady commit since it kept explicitly.
47    /// - The last steady transaction makes an effect similar to "long-lived" read transaction
48    ///   since prevents reuse of pages freed by newer write transactions, thus the any data
49    ///   changes will be placed in newly allocated pages.
50    /// - To avoid rapid database growth, the system will sync data and issue a steady commit-point
51    ///   to resume reuse pages, each time there is insufficient space and before increasing the
52    ///   size of the file on disk.
53    ///
54    /// In other words, with
55    /// [`SyncMode::SafeNoSync`] flag MDBX protects you from the whole database corruption, at the
56    /// cost increasing database size and/or number of disk IOPs. So, [`SyncMode::SafeNoSync`]
57    /// flag could be used with [`Environment::sync()`](crate::Environment::sync) as alternatively
58    /// for batch committing or nested transaction (in some cases).
59    ///
60    /// The number and volume of of disk IOPs with [`SyncMode::SafeNoSync`] flag will exactly the
61    /// as without any no-sync flags. However, you should expect a larger process's work set
62    /// and significantly worse a locality of reference, due to the more intensive allocation
63    /// of previously unused pages and increase the size of the database.
64    SafeNoSync,
65
66    /// Don't sync anything and wipe previous steady commits.
67    ///
68    /// Don't flush system buffers to disk when committing a transaction.
69    /// This optimization means a system crash can corrupt the database, if buffers are not yet
70    /// flushed to disk. Depending on the platform and hardware, with [`SyncMode::UtterlyNoSync`]
71    /// you may get a multiple increase of write performance, even 100 times or more.
72    ///
73    /// If the filesystem preserves write order (which is rare and never provided unless explicitly
74    /// noted) and the [`WriteMap`](crate::EnvironmentKind::WriteMap) and
75    /// [`EnvironmentFlags::liforeclaim`] flags are not used, then a system crash can't corrupt
76    /// the database, but you can lose the last transactions, if at least one buffer is not yet
77    /// flushed to disk. The risk is governed by how often the system flushes dirty buffers to
78    /// disk and how often [`Environment::sync()`](crate::Environment::sync) is called. So,
79    /// transactions exhibit ACPI (atomicity, consistency, isolation) properties and only lose D
80    /// (durability). I.e. database integrity is maintained, but a system crash may undo the
81    /// final transactions.
82    ///
83    /// Otherwise, if the filesystem not preserves write order (which is typically) or
84    /// [`WriteMap`](crate::EnvironmentKind::WriteMap) or [`EnvironmentFlags::liforeclaim`] flags
85    /// are used, you should expect the corrupted database after a system crash.
86    ///
87    /// So, most important thing about [`SyncMode::UtterlyNoSync`]:
88    /// - A system crash immediately after commit the write transaction high likely lead to
89    ///   database corruption.
90    /// - Successful completion of [`Environment::sync(force=true`)](crate::Environment::sync)
91    ///   after one or more committed transactions guarantees consistency and durability.
92    /// - BUT by committing two or more transactions you back database into a weak state, in which
93    ///   a system crash may lead to database corruption! In case single transaction after
94    ///   [`Environment::sync()`](crate::Environment::sync), you may lose transaction itself, but
95    ///   not a whole database.
96    ///
97    /// Nevertheless, [`SyncMode::UtterlyNoSync`] provides "weak" durability in
98    /// case of an application crash (but no durability on system failure), and therefore may
99    /// be very useful in scenarios where data durability is not required over a system failure
100    /// (e.g for short-lived data), or if you can take such risk.
101    UtterlyNoSync,
102}
103
104impl Default for SyncMode {
105    fn default() -> Self {
106        Self::Durable
107    }
108}
109
110#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
111pub enum Mode {
112    ReadOnly,
113    ReadWrite { sync_mode: SyncMode },
114}
115
116impl Default for Mode {
117    fn default() -> Self {
118        Self::ReadWrite {
119            sync_mode: SyncMode::default(),
120        }
121    }
122}
123
124impl From<Mode> for EnvironmentFlags {
125    fn from(mode: Mode) -> Self {
126        Self {
127            mode,
128            ..Default::default()
129        }
130    }
131}
132
133#[derive(Clone, Copy, Debug, Default, Serialize, Deserialize)]
134pub struct EnvironmentFlags {
135    pub no_sub_dir: bool,
136    pub exclusive: bool,
137    /// Flag is intended to open an existing sub-database which was created with unknown flags
138    /// In such cases, instead of returning the `MDBX_INCOMPATIBLE` error, the sub-database will be
139    /// opened with flags which it was created, and then an application could determine the actual
140    /// flags.
141    pub accede: bool,
142    pub mode: Mode,
143    pub no_rdahead: bool,
144    pub no_meminit: bool,
145    pub coalesce: bool,
146    pub liforeclaim: bool,
147}
148
149impl EnvironmentFlags {
150    /// Configures the mdbx flags to use when opening the environment.
151    pub(crate) const fn make_flags(&self) -> ffi::MDBX_env_flags_t {
152        let mut flags = 0;
153
154        if self.no_sub_dir {
155            flags |= ffi::MDBX_NOSUBDIR;
156        }
157
158        if self.exclusive {
159            flags |= ffi::MDBX_EXCLUSIVE;
160        }
161
162        if self.accede {
163            flags |= ffi::MDBX_ACCEDE;
164        }
165
166        match self.mode {
167            Mode::ReadOnly => {
168                flags |= ffi::MDBX_RDONLY;
169            }
170            Mode::ReadWrite { sync_mode } => {
171                flags |= match sync_mode {
172                    SyncMode::Durable => ffi::MDBX_SYNC_DURABLE,
173                    SyncMode::NoMetaSync => ffi::MDBX_NOMETASYNC,
174                    SyncMode::SafeNoSync => ffi::MDBX_SAFE_NOSYNC,
175                    SyncMode::UtterlyNoSync => ffi::MDBX_UTTERLY_NOSYNC,
176                };
177            }
178        }
179
180        if self.no_rdahead {
181            flags |= ffi::MDBX_NORDAHEAD;
182        }
183
184        if self.no_meminit {
185            flags |= ffi::MDBX_NOMEMINIT;
186        }
187
188        if self.coalesce {
189            flags |= ffi::MDBX_COALESCE;
190        }
191
192        if self.liforeclaim {
193            flags |= ffi::MDBX_LIFORECLAIM;
194        }
195
196        flags |= ffi::MDBX_NOTLS;
197
198        flags
199    }
200}
201
202bitflags! {
203    #[doc="Database options."]
204    #[derive(Default, Clone, Copy)]
205    pub struct DatabaseFlags: MDBX_env_flags_t {
206        const REVERSE_KEY = MDBX_REVERSEKEY;
207        const DUP_SORT = MDBX_DUPSORT;
208        const INTEGER_KEY = MDBX_INTEGERKEY;
209        const DUP_FIXED = MDBX_DUPFIXED;
210        const INTEGER_DUP = MDBX_INTEGERDUP;
211        const REVERSE_DUP = MDBX_REVERSEDUP;
212        const CREATE = MDBX_CREATE;
213        const ACCEDE = MDBX_DB_ACCEDE;
214    }
215}
216
217bitflags! {
218    #[doc="Write options."]
219    #[derive(Default, Clone, Copy)]
220    pub struct WriteFlags: MDBX_env_flags_t {
221        const UPSERT = MDBX_UPSERT;
222        const NO_OVERWRITE = MDBX_NOOVERWRITE;
223        const NO_DUP_DATA = MDBX_NODUPDATA;
224        const CURRENT = MDBX_CURRENT;
225        const ALLDUPS = MDBX_ALLDUPS;
226        const RESERVE = MDBX_RESERVE;
227        const APPEND = MDBX_APPEND;
228        const APPEND_DUP = MDBX_APPENDDUP;
229        const MULTIPLE = MDBX_MULTIPLE;
230    }
231}