diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8059f4ee..f864f0f4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -372,6 +372,31 @@ jobs: # run: valgrind --error-exitcode=1 --leak-check=full --show-leak-kinds=all ./target/debug/foo # working-directory: integration + docs: + name: docs + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: Cache cargo build and registry + uses: actions/cache@v3 + with: + path: | + ~/.cargo/registry + ~/.cargo/git + target + key: ubuntu-latest-docs-${{ hashFiles('**/Cargo.lock') }} + restore-keys: | + ubuntu-latest-docs- + - uses: actions-rs/toolchain@v1 + with: + toolchain: ${{ env.nightly }} + override: true + - name: "doc --lib --all-features" + run: cargo doc --lib --no-deps --all-features + env: + RUSTFLAGS: --cfg docsrs + RUSTDOCFLAGS: --cfg docsrs -Dwarnings + coverage: name: coverage runs-on: ubuntu-latest diff --git a/Cargo.toml b/Cargo.toml index 7b9b83a9..f3b4f502 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "orderwal" -version = "0.2.1" +version = "0.3.0" edition = "2021" repository = "https://github.com/al8n/orderwal" homepage = "https://github.com/al8n/orderwal" @@ -27,7 +27,7 @@ xxhash64 = ["dbutils/xxhash64", "std"] among = { version = "0.1", default-features = false, features = ["either"] } bitflags = { version = "1", default-features = false } dbutils = { version = "0.3", default-features = false, features = ["crc32fast"] } -rarena-allocator = { version = "0.2", default-features = false, features = ["memmap"] } +rarena-allocator = { version = "0.3", default-features = false, features = ["memmap"] } crossbeam-skiplist = { version = "0.1", default-features = false, package = "crossbeam-skiplist-pr1132" } paste = "1" thiserror = "1" diff --git a/examples/zero_cost.rs b/examples/zero_cost.rs index 45365782..a3b87670 100644 --- a/examples/zero_cost.rs +++ b/examples/zero_cost.rs @@ -3,7 +3,6 @@ use std::{cmp, sync::Arc, thread::spawn}; use orderwal::{ swmr::generic::{Comparable, Equivalent, GenericBuilder, KeyRef, Type, TypeRef}, utils::*, - OpenOptions, }; #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] @@ -137,13 +136,11 @@ fn main() { let mut wal = unsafe { GenericBuilder::new() - .map_mut::( - &path, - OpenOptions::new() - .create_new(Some(1024 * 1024)) - .write(true) - .read(true), - ) + .with_capacity(1024 * 1024) + .with_create_new(true) + .with_read(true) + .with_write(true) + .map_mut::(&path) .unwrap() }; diff --git a/src/builder.rs b/src/builder.rs index 29c6ad27..5dc3f516 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -1,4 +1,5 @@ use checksum::BuildChecksumer; +use options::ArenaOptionsExt; use wal::{sealed::Constructor, Wal}; use super::*; @@ -210,33 +211,6 @@ impl Builder { self.opts.sync_on_write() } - /// Returns the bits of the page size. - /// - /// Configures the anonymous memory map to be allocated using huge pages. - /// - /// This option corresponds to the `MAP_HUGETLB` flag on Linux. It has no effect on Windows. - /// - /// The size of the requested page can be specified in page bits. - /// If not provided, the system default is requested. - /// The requested length should be a multiple of this, or the mapping will fail. - /// - /// This option has no effect on file-backed memory maps. - /// - /// The default value is `None`. - /// - /// ## Example - /// - /// ```rust - /// use orderwal::Builder; - /// - /// let options = Builder::new().with_huge(64); - /// assert_eq!(options.huge(), Some(64)); - /// ``` - #[inline] - pub const fn huge(&self) -> Option { - self.opts.huge() - } - /// Sets the capacity of the WAL. /// /// This configuration will be ignored when using file-backed memory maps. @@ -289,69 +263,404 @@ impl Builder { self } - /// Returns the bits of the page size. + /// Sets the WAL to sync on write. /// - /// Configures the anonymous memory map to be allocated using huge pages. + /// The default value is `true`. /// - /// This option corresponds to the `MAP_HUGETLB` flag on Linux. It has no effect on Windows. + /// ## Example /// - /// The size of the requested page can be specified in page bits. - /// If not provided, the system default is requested. - /// The requested length should be a multiple of this, or the mapping will fail. + /// ```rust + /// use orderwal::Builder; /// - /// This option has no effect on file-backed memory maps. + /// let options = Builder::new().with_sync_on_write(false); + /// assert_eq!(options.sync_on_write(), false); + /// ``` + #[inline] + pub const fn with_sync_on_write(mut self, sync: bool) -> Self { + self.opts = self.opts.with_sync_on_write(sync); + self + } + + /// Sets the magic version. /// - /// The default value is `None`. + /// The default value is `0`. /// /// ## Example /// /// ```rust /// use orderwal::Builder; /// - /// let options = Builder::new().with_huge(64); - /// assert_eq!(options.huge(), Some(64)); + /// let options = Builder::new().with_magic_version(1); + /// assert_eq!(options.magic_version(), 1); /// ``` #[inline] - pub const fn with_huge(mut self, page_bits: u8) -> Self { - self.opts = self.opts.with_huge(page_bits); + pub const fn with_magic_version(mut self, version: u16) -> Self { + self.opts = self.opts.with_magic_version(version); self } +} - /// Sets the WAL to sync on write. +impl Builder { + /// Sets the option for read access. /// - /// The default value is `true`. + /// This option, when true, will indicate that the file should be + /// `read`-able if opened. /// - /// ## Example + /// ## Examples /// /// ```rust /// use orderwal::Builder; /// - /// let options = Builder::new().with_sync_on_write(false); - /// assert_eq!(options.sync_on_write(), false); + /// let opts = Builder::new().with_read(true); /// ``` #[inline] - pub const fn with_sync_on_write(mut self, sync: bool) -> Self { - self.opts = self.opts.with_sync_on_write(sync); + pub fn with_read(mut self, read: bool) -> Self { + self.opts.read = read; self } - /// Sets the magic version. + /// Sets the option for write access. /// - /// The default value is `0`. + /// This option, when true, will indicate that the file should be + /// `write`-able if opened. /// - /// ## Example + /// If the file already exists, any write calls on it will overwrite its + /// contents, without truncating it. + /// + /// ## Examples /// /// ```rust /// use orderwal::Builder; /// - /// let options = Builder::new().with_magic_version(1); - /// assert_eq!(options.magic_version(), 1); + /// let opts = Builder::new().with_write(true); /// ``` #[inline] - pub const fn with_magic_version(mut self, version: u16) -> Self { - self.opts = self.opts.with_magic_version(version); + pub fn with_write(mut self, write: bool) -> Self { + self.opts.write = write; self } + + /// Sets the option for the append mode. + /// + /// This option, when true, means that writes will append to a file instead + /// of overwriting previous contents. + /// Note that setting `.write(true).append(true)` has the same effect as + /// setting only `.append(true)`. + /// + /// For most filesystems, the operating system guarantees that all writes are + /// atomic: no writes get mangled because another process writes at the same + /// time. + /// + /// One maybe obvious note when using append-mode: make sure that all data + /// that belongs together is written to the file in one operation. This + /// can be done by concatenating strings before passing them to [`write()`], + /// or using a buffered writer (with a buffer of adequate size), + /// and calling [`flush()`] when the message is complete. + /// + /// If a file is opened with both read and append access, beware that after + /// opening, and after every write, the position for reading may be set at the + /// end of the file. So, before writing, save the current position (using + /// [seek]\([SeekFrom](std::io::SeekFrom)::[Current]\(opts))), and restore it before the next read. + /// + /// ## Note + /// + /// This function doesn't create the file if it doesn't exist. Use the + /// [`Options::with_create`] method to do so. + /// + /// [`write()`]: std::io::Write::write "io::Write::write" + /// [`flush()`]: std::io::Write::flush "io::Write::flush" + /// [seek]: std::io::Seek::seek "io::Seek::seek" + /// [Current]: std::io::SeekFrom::Current "io::SeekFrom::Current" + /// + /// ## Examples + /// + /// ```rust + /// use orderwal::Builder; + /// + /// let opts = Builder::new().with_append(true); + /// ``` + #[inline] + pub fn with_append(mut self, append: bool) -> Self { + self.opts.write = true; + self.opts.append = append; + self + } + + /// Sets the option for truncating a previous file. + /// + /// If a file is successfully opened with this option set it will truncate + /// the file to opts length if it already exists. + /// + /// The file must be opened with write access for truncate to work. + /// + /// ## Examples + /// + /// ```rust + /// use orderwal::Builder; + /// + /// let opts = Builder::new().with_write(true).with_truncate(true); + /// ``` + #[inline] + pub fn with_truncate(mut self, truncate: bool) -> Self { + self.opts.truncate = truncate; + self.opts.write = true; + self + } + + /// Sets the option to create a new file, or open it if it already exists. + /// If the file does not exist, it is created and set the lenght of the file to the given size. + /// + /// In order for the file to be created, [`Options::with_write`] or + /// [`Options::with_append`] access must be used. + /// + /// See also [`std::fs::write()`][std::fs::write] for a simple function to + /// create a file with some given data. + /// + /// ## Examples + /// + /// ```rust + /// use orderwal::Builder; + /// + /// let opts = Builder::new().with_write(true).with_create(true); + /// ``` + #[inline] + pub fn with_create(mut self, val: bool) -> Self { + self.opts.create = val; + self + } + + /// Sets the option to create a new file and set the file length to the given value, failing if it already exists. + /// + /// No file is allowed to exist at the target location, also no (dangling) symlink. In this + /// way, if the call succeeds, the file returned is guaranteed to be new. + /// + /// This option is useful because it is atomic. Otherwise between checking + /// whether a file exists and creating a new one, the file may have been + /// created by another process (a TOCTOU race condition / attack). + /// + /// If `.with_create_new(true)` is set, [`.with_create()`] and [`.with_truncate()`] are + /// ignored. + /// + /// The file must be opened with write or append access in order to create + /// a new file. + /// + /// [`.with_create()`]: Builder::with_create + /// [`.with_truncate()`]: Builder::with_truncate + /// + /// ## Examples + /// + /// ```rust + /// use orderwal::Builder; + /// + /// let opts = Builder::new() + /// .with_write(true) + /// .with_create_new(true); + /// ``` + #[inline] + pub fn with_create_new(mut self, val: bool) -> Self { + self.opts.create_new = val; + self + } + + /// Configures the anonymous memory map to be suitable for a process or thread stack. + /// + /// This option corresponds to the `MAP_STACK` flag on Linux. It has no effect on Windows. + /// + /// This option has no effect on file-backed memory maps and vec backed [`Wal`](crate::Wal). + /// + /// ## Example + /// + /// ``` + /// use orderwal::Builder; + /// + /// let stack = Builder::new().with_stack(true); + /// ``` + #[inline] + pub fn with_stack(mut self, stack: bool) -> Self { + self.opts.stack = stack; + self + } + + /// Configures the anonymous memory map to be allocated using huge pages. + /// + /// This option corresponds to the `MAP_HUGETLB` flag on Linux. It has no effect on Windows. + /// + /// The size of the requested page can be specified in page bits. If not provided, the system + /// default is requested. The requested length should be a multiple of this, or the mapping + /// will fail. + /// + /// This option has no effect on file-backed memory maps and vec backed [`Wal`](crate::Wal). + /// + /// ## Example + /// + /// ``` + /// use orderwal::Builder; + /// + /// let opts = Builder::new().with_huge(Some(8)); + /// ``` + #[inline] + pub fn with_huge(mut self, page_bits: Option) -> Self { + self.opts.huge = page_bits; + self + } + + /// Populate (prefault) page tables for a mapping. + /// + /// For a file mapping, this causes read-ahead on the file. This will help to reduce blocking on page faults later. + /// + /// This option corresponds to the `MAP_POPULATE` flag on Linux. It has no effect on Windows. + /// + /// This option has no effect on vec backed [`Wal`](crate::Wal). + /// + /// ## Example + /// + /// ``` + /// use orderwal::Builder; + /// + /// let opts = Builder::new().with_populate(true); + /// ``` + #[inline] + pub fn with_populate(mut self, populate: bool) -> Self { + self.opts.populate = populate; + self + } +} + +impl Builder { + /// Returns `true` if the file should be opened with read access. + /// + /// ## Examples + /// + /// ```rust + /// use orderwal::Builder; + /// + /// let opts = Builder::new().with_read(true); + /// assert_eq!(opts.read(), true); + /// ``` + #[inline] + pub const fn read(&self) -> bool { + self.opts.read + } + + /// Returns `true` if the file should be opened with write access. + /// + /// ## Examples + /// + /// ```rust + /// use orderwal::Builder; + /// + /// let opts = Builder::new().with_write(true); + /// assert_eq!(opts.write(), true); + /// ``` + #[inline] + pub const fn write(&self) -> bool { + self.opts.write + } + + /// Returns `true` if the file should be opened with append access. + /// + /// ## Examples + /// + /// ```rust + /// use orderwal::Builder; + /// + /// let opts = Builder::new().with_append(true); + /// assert_eq!(opts.append(), true); + /// ``` + #[inline] + pub const fn append(&self) -> bool { + self.opts.append + } + + /// Returns `true` if the file should be opened with truncate access. + /// + /// ## Examples + /// + /// ```rust + /// use orderwal::Builder; + /// + /// let opts = Builder::new().with_truncate(true); + /// assert_eq!(opts.truncate(), true); + /// ``` + #[inline] + pub const fn truncate(&self) -> bool { + self.opts.truncate + } + + /// Returns `true` if the file should be created if it does not exist. + /// + /// ## Examples + /// + /// ```rust + /// use orderwal::Builder; + /// + /// let opts = Builder::new().with_create(true); + /// assert_eq!(opts.create(), true); + /// ``` + #[inline] + pub const fn create(&self) -> bool { + self.opts.create + } + + /// Returns `true` if the file should be created if it does not exist and fail if it does. + /// + /// ## Examples + /// + /// ```rust + /// use orderwal::Builder; + /// + /// let opts = Builder::new().with_create_new(true); + /// assert_eq!(opts.create_new(), true); + /// ``` + #[inline] + pub const fn create_new(&self) -> bool { + self.opts.create_new + } + + /// Returns `true` if the memory map should be suitable for a process or thread stack. + /// + /// ## Examples + /// + /// ```rust + /// use orderwal::Builder; + /// + /// let opts = Builder::new().with_stack(true); + /// assert_eq!(opts.stack(), true); + /// ``` + #[inline] + pub const fn stack(&self) -> bool { + self.opts.stack + } + + /// Returns the page bits of the memory map. + /// + /// ## Examples + /// + /// ```rust + /// use orderwal::Builder; + /// + /// let opts = Builder::new().with_huge(Some(8)); + /// assert_eq!(opts.huge(), Some(8)); + /// ``` + #[inline] + pub const fn huge(&self) -> Option { + self.opts.huge + } + + /// Returns `true` if the memory map should populate (prefault) page tables for a mapping. + /// + /// ## Examples + /// + /// ```rust + /// use orderwal::Builder; + /// + /// let opts = Builder::new().with_populate(true); + /// assert_eq!(opts.populate(), true); + /// ``` + #[inline] + pub const fn populate(&self) -> bool { + self.opts.populate + } } impl Builder { @@ -396,9 +705,9 @@ impl Builder { W: Wal, { let Self { opts, cmp, cks } = self; - let mmap_opts = MmapOptions::new().len(opts.capacity()); arena_options(opts.reserved()) - .map_anon(mmap_opts) + .merge(&opts) + .map_anon() .map_err(Into::into) .and_then(|arena| >::new_in(arena, opts, cmp, cks).map(W::from_core)) } @@ -417,14 +726,14 @@ impl Builder { /// /// ```rust /// use orderwal::{swmr::OrderWal, Builder}; - /// # use orderwal::OpenOptions; /// /// # let dir = tempfile::tempdir().unwrap(); /// # let path = dir.path().join("map.wal"); /// /// # let wal = unsafe { /// # Builder::new() - /// # .map_mut::(&path, OpenOptions::default().read(true).write(true).create(Some(1000))) + /// # .with_capacity(1000).with_create(true).with_read(true).with_write(true) + /// # .map_mut::(&path) /// # .unwrap() /// # }; /// @@ -459,14 +768,14 @@ impl Builder { /// /// ```rust /// use orderwal::{swmr::OrderWal, Builder}; - /// # use orderwal::OpenOptions; /// /// # let dir = tempfile::tempdir().unwrap(); /// # let path = dir.path().join("map_with_path_builder.wal"); /// /// # let wal = unsafe { /// # Builder::new() - /// # .map_mut::(&path, OpenOptions::default().read(true).write(true).create(Some(1000))) + /// # .with_capacity(1000).with_create(true).with_read(true).with_write(true) + /// # .map_mut::(&path) /// # .unwrap() /// # }; /// @@ -486,12 +795,12 @@ impl Builder { W: Wal, W::Pointer: Ord + 'static, { - let open_options = OpenOptions::default().read(true); - let Self { opts, cmp, cks } = self; arena_options(opts.reserved()) - .map_with_path_builder(path_builder, open_options, MmapOptions::new()) + .merge(&opts) + .with_read(true) + .map_with_path_builder(path_builder) .map_err(|e| e.map_right(Into::into)) .and_then(|arena| { >::replay(arena, Options::new(), true, cmp, cks) @@ -513,18 +822,22 @@ impl Builder { /// ## Example /// /// ```rust - /// use orderwal::{swmr::OrderWal, Builder, OpenOptions}; + /// use orderwal::{swmr::OrderWal, Builder}; /// /// let dir = tempfile::tempdir().unwrap(); /// let path = dir.path().join("map_mut_with_path_builder_example.wal"); /// /// let wal = unsafe { /// Builder::new() - /// .map_mut::(&path, OpenOptions::default().read(true).write(true).create(Some(1000))) - /// .unwrap() + /// .with_create_new(true) + /// .with_read(true) + /// .with_write(true) + /// .with_capacity(1000) + /// .map_mut::(&path) + /// .unwrap() /// }; /// ``` - pub unsafe fn map_mut(self, path: P, open_opts: OpenOptions) -> Result + pub unsafe fn map_mut(self, path: P) -> Result where C: Comparator + CheapClone + 'static, S: BuildChecksumer, @@ -532,7 +845,7 @@ impl Builder { W: Wal, { self - .map_mut_with_path_builder::(|| Ok(path.as_ref().to_path_buf()), open_opts) + .map_mut_with_path_builder::(|| Ok(path.as_ref().to_path_buf())) .map_err(|e| e.unwrap_right()) } @@ -549,23 +862,25 @@ impl Builder { /// ## Example /// /// ```rust - /// use orderwal::{swmr::OrderWal, Builder, OpenOptions}; + /// use orderwal::{swmr::OrderWal, Builder}; /// /// let dir = tempfile::tempdir().unwrap(); /// /// let wal = unsafe { /// Builder::new() - /// .map_mut_with_path_builder::( - /// || Ok(dir.path().join("map_mut_with_path_builder_example.wal")), - /// OpenOptions::default().read(true).write(true).create(Some(1000)), - /// ) - /// .unwrap() + /// .with_create_new(true) + /// .with_read(true) + /// .with_write(true) + /// .with_capacity(1000) + /// .map_mut_with_path_builder::( + /// || Ok(dir.path().join("map_mut_with_path_builder_example.wal")), + /// ) + /// .unwrap() /// }; /// ``` pub unsafe fn map_mut_with_path_builder( self, path_builder: PB, - open_options: OpenOptions, ) -> Result> where PB: FnOnce() -> Result, @@ -578,7 +893,8 @@ impl Builder { let Self { opts, cmp, cks } = self; arena_options(opts.reserved()) - .map_mut(path, open_options, MmapOptions::new()) + .merge(&opts) + .map_mut(path) .map_err(Into::into) .and_then(|arena| { if !exist { diff --git a/src/lib.rs b/src/lib.rs index 87b9e0bc..f5360cc2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -14,11 +14,9 @@ use crossbeam_skiplist::SkipSet; use error::Error; use rarena_allocator::{ either::{self, Either}, - Allocator, ArenaOptions, Freelist, Memory, MmapOptions, + Allocator, Buffer, Freelist, Options as ArenaOptions, }; -pub use rarena_allocator::OpenOptions; - #[cfg(feature = "std")] extern crate std; diff --git a/src/options.rs b/src/options.rs index 092460a8..80d366e0 100644 --- a/src/options.rs +++ b/src/options.rs @@ -5,9 +5,19 @@ pub struct Options { maximum_value_size: u32, sync_on_write: bool, magic_version: u16, - huge: Option, - cap: u32, + cap: Option, reserved: u32, + + pub(crate) read: bool, + pub(crate) write: bool, + pub(crate) create_new: bool, + pub(crate) create: bool, + pub(crate) truncate: bool, + pub(crate) append: bool, + + pub(crate) stack: bool, + pub(crate) populate: bool, + pub(crate) huge: Option, } impl Default for Options { @@ -38,8 +48,16 @@ impl Options { sync_on_write: true, magic_version: 0, huge: None, - cap: 0, + cap: None, reserved: 0, + read: false, + write: false, + create_new: false, + create: false, + truncate: false, + append: false, + stack: false, + populate: false, } } @@ -115,7 +133,10 @@ impl Options { /// ``` #[inline] pub const fn capacity(&self) -> u32 { - self.cap + match self.cap { + Some(cap) => cap, + None => 0, + } } /// Returns the maximum key length. @@ -169,33 +190,6 @@ impl Options { self.sync_on_write } - /// Returns the bits of the page size. - /// - /// Configures the anonymous memory map to be allocated using huge pages. - /// - /// This option corresponds to the `MAP_HUGETLB` flag on Linux. It has no effect on Windows. - /// - /// The size of the requested page can be specified in page bits. - /// If not provided, the system default is requested. - /// The requested length should be a multiple of this, or the mapping will fail. - /// - /// This option has no effect on file-backed memory maps. - /// - /// The default value is `None`. - /// - /// ## Example - /// - /// ```rust - /// use orderwal::Options; - /// - /// let options = Options::new().with_huge(64); - /// assert_eq!(options.huge(), Some(64)); - /// ``` - #[inline] - pub const fn huge(&self) -> Option { - self.huge - } - /// Sets the capacity of the WAL. /// /// This configuration will be ignored when using file-backed memory maps. @@ -212,7 +206,7 @@ impl Options { /// ``` #[inline] pub const fn with_capacity(mut self, cap: u32) -> Self { - self.cap = cap; + self.cap = Some(cap); self } @@ -248,67 +242,434 @@ impl Options { self } - /// Returns the bits of the page size. + /// Sets the WAL to sync on write. /// - /// Configures the anonymous memory map to be allocated using huge pages. + /// The default value is `true`. /// - /// This option corresponds to the `MAP_HUGETLB` flag on Linux. It has no effect on Windows. + /// ## Example /// - /// The size of the requested page can be specified in page bits. - /// If not provided, the system default is requested. - /// The requested length should be a multiple of this, or the mapping will fail. + /// ```rust + /// use orderwal::Options; /// - /// This option has no effect on file-backed memory maps. + /// let options = Options::new().with_sync_on_write(false); + /// assert_eq!(options.sync_on_write(), false); + /// ``` + #[inline] + pub const fn with_sync_on_write(mut self, sync: bool) -> Self { + self.sync_on_write = sync; + self + } + + /// Sets the magic version. /// - /// The default value is `None`. + /// The default value is `0`. /// /// ## Example /// /// ```rust /// use orderwal::Options; /// - /// let options = Options::new().with_huge(64); - /// assert_eq!(options.huge(), Some(64)); + /// let options = Options::new().with_magic_version(1); + /// assert_eq!(options.magic_version(), 1); /// ``` #[inline] - pub const fn with_huge(mut self, page_bits: u8) -> Self { - self.huge = Some(page_bits); + pub const fn with_magic_version(mut self, version: u16) -> Self { + self.magic_version = version; self } +} - /// Sets the WAL to sync on write. +impl Options { + /// Sets the option for read access. /// - /// The default value is `true`. + /// This option, when true, will indicate that the file should be + /// `read`-able if opened. /// - /// ## Example + /// ## Examples /// /// ```rust /// use orderwal::Options; /// - /// let options = Options::new().with_sync_on_write(false); - /// assert_eq!(options.sync_on_write(), false); + /// let opts = Options::new().with_read(true); /// ``` #[inline] - pub const fn with_sync_on_write(mut self, sync: bool) -> Self { - self.sync_on_write = sync; + pub fn with_read(mut self, read: bool) -> Self { + self.read = read; self } - /// Sets the magic version. + /// Sets the option for write access. /// - /// The default value is `0`. + /// This option, when true, will indicate that the file should be + /// `write`-able if opened. /// - /// ## Example + /// If the file already exists, any write calls on it will overwrite its + /// contents, without truncating it. + /// + /// ## Examples /// /// ```rust /// use orderwal::Options; /// - /// let options = Options::new().with_magic_version(1); - /// assert_eq!(options.magic_version(), 1); + /// let opts = Options::new().with_write(true); /// ``` #[inline] - pub const fn with_magic_version(mut self, version: u16) -> Self { - self.magic_version = version; + pub fn with_write(mut self, write: bool) -> Self { + self.write = write; + self + } + + /// Sets the option for the append mode. + /// + /// This option, when true, means that writes will append to a file instead + /// of overwriting previous contents. + /// Note that setting `.write(true).append(true)` has the same effect as + /// setting only `.append(true)`. + /// + /// For most filesystems, the operating system guarantees that all writes are + /// atomic: no writes get mangled because another process writes at the same + /// time. + /// + /// One maybe obvious note when using append-mode: make sure that all data + /// that belongs together is written to the file in one operation. This + /// can be done by concatenating strings before passing them to [`write()`], + /// or using a buffered writer (with a buffer of adequate size), + /// and calling [`flush()`] when the message is complete. + /// + /// If a file is opened with both read and append access, beware that after + /// opening, and after every write, the position for reading may be set at the + /// end of the file. So, before writing, save the current position (using + /// [seek]\([SeekFrom](std::io::SeekFrom)::[Current]\(opts))), and restore it before the next read. + /// + /// ## Note + /// + /// This function doesn't create the file if it doesn't exist. Use the + /// [`Options::with_create`] method to do so. + /// + /// [`write()`]: std::io::Write::write "io::Write::write" + /// [`flush()`]: std::io::Write::flush "io::Write::flush" + /// [seek]: std::io::Seek::seek "io::Seek::seek" + /// [Current]: std::io::SeekFrom::Current "io::SeekFrom::Current" + /// + /// ## Examples + /// + /// ```rust + /// use orderwal::Options; + /// + /// let opts = Options::new().with_append(true); + /// ``` + #[inline] + pub fn with_append(mut self, append: bool) -> Self { + self.write = true; + self.append = append; + self + } + + /// Sets the option for truncating a previous file. + /// + /// If a file is successfully opened with this option set it will truncate + /// the file to opts length if it already exists. + /// + /// The file must be opened with write access for truncate to work. + /// + /// ## Examples + /// + /// ```rust + /// use orderwal::Options; + /// + /// let opts = Options::new().with_write(true).with_truncate(true); + /// ``` + #[inline] + pub fn with_truncate(mut self, truncate: bool) -> Self { + self.truncate = truncate; + self.write = true; + self + } + + /// Sets the option to create a new file, or open it if it already exists. + /// If the file does not exist, it is created and set the lenght of the file to the given size. + /// + /// In order for the file to be created, [`Options::with_write`] or + /// [`Options::with_append`] access must be used. + /// + /// See also [`std::fs::write()`][std::fs::write] for a simple function to + /// create a file with some given data. + /// + /// ## Examples + /// + /// ```rust + /// use orderwal::Options; + /// + /// let opts = Options::new().with_write(true).with_create(true); + /// ``` + #[inline] + pub fn with_create(mut self, val: bool) -> Self { + self.create = val; + self + } + + /// Sets the option to create a new file and set the file length to the given value, failing if it already exists. + /// + /// No file is allowed to exist at the target location, also no (dangling) symlink. In this + /// way, if the call succeeds, the file returned is guaranteed to be new. + /// + /// This option is useful because it is atomic. Otherwise between checking + /// whether a file exists and creating a new one, the file may have been + /// created by another process (a TOCTOU race condition / attack). + /// + /// If `.with_create_new(true)` is set, [`.with_create()`] and [`.with_truncate()`] are + /// ignored. + /// + /// The file must be opened with write or append access in order to create + /// a new file. + /// + /// [`.with_create()`]: Options::with_create + /// [`.with_truncate()`]: Options::with_truncate + /// + /// ## Examples + /// + /// ```rust + /// use orderwal::Options; + /// + /// let file = Options::new() + /// .with_write(true) + /// .with_create_new(true); + /// ``` + #[inline] + pub fn with_create_new(mut self, val: bool) -> Self { + self.create_new = val; + self + } + + /// Configures the anonymous memory map to be suitable for a process or thread stack. + /// + /// This option corresponds to the `MAP_STACK` flag on Linux. It has no effect on Windows. + /// + /// This option has no effect on file-backed memory maps and vec backed [`Wal`](crate::Wal). + /// + /// ## Example + /// + /// ``` + /// use orderwal::Options; + /// + /// let stack = Options::new().with_stack(true); + /// ``` + #[inline] + pub fn with_stack(mut self, stack: bool) -> Self { + self.stack = stack; self } + + /// Configures the anonymous memory map to be allocated using huge pages. + /// + /// This option corresponds to the `MAP_HUGETLB` flag on Linux. It has no effect on Windows. + /// + /// The size of the requested page can be specified in page bits. If not provided, the system + /// default is requested. The requested length should be a multiple of this, or the mapping + /// will fail. + /// + /// This option has no effect on file-backed memory maps and vec backed [`Wal`](crate::Wal). + /// + /// ## Example + /// + /// ``` + /// use orderwal::Options; + /// + /// let stack = Options::new().with_huge(Some(8)); + /// ``` + #[inline] + pub fn with_huge(mut self, page_bits: Option) -> Self { + self.huge = page_bits; + self + } + + /// Populate (prefault) page tables for a mapping. + /// + /// For a file mapping, this causes read-ahead on the file. This will help to reduce blocking on page faults later. + /// + /// This option corresponds to the `MAP_POPULATE` flag on Linux. It has no effect on Windows. + /// + /// This option has no effect on vec backed [`Wal`](crate::Wal). + /// + /// ## Example + /// + /// ``` + /// use orderwal::Options; + /// + /// let opts = Options::new().with_populate(true); + /// ``` + #[inline] + pub fn with_populate(mut self, populate: bool) -> Self { + self.populate = populate; + self + } +} + +impl Options { + /// Returns `true` if the file should be opened with read access. + /// + /// ## Examples + /// + /// ```rust + /// use orderwal::Options; + /// + /// let opts = Options::new().with_read(true); + /// assert_eq!(opts.read(), true); + /// ``` + #[inline] + + pub const fn read(&self) -> bool { + self.read + } + + /// Returns `true` if the file should be opened with write access. + /// + /// ## Examples + /// + /// ```rust + /// use orderwal::Options; + /// + /// let opts = Options::new().with_write(true); + /// assert_eq!(opts.write(), true); + /// ``` + #[inline] + + pub const fn write(&self) -> bool { + self.write + } + + /// Returns `true` if the file should be opened with append access. + /// + /// ## Examples + /// + /// ```rust + /// use orderwal::Options; + /// + /// let opts = Options::new().with_append(true); + /// assert_eq!(opts.append(), true); + /// ``` + #[inline] + + pub const fn append(&self) -> bool { + self.append + } + + /// Returns `true` if the file should be opened with truncate access. + /// + /// ## Examples + /// + /// ```rust + /// use orderwal::Options; + /// + /// let opts = Options::new().with_truncate(true); + /// assert_eq!(opts.truncate(), true); + /// ``` + #[inline] + + pub const fn truncate(&self) -> bool { + self.truncate + } + + /// Returns `true` if the file should be created if it does not exist. + /// + /// ## Examples + /// + /// ```rust + /// use orderwal::Options; + /// + /// let opts = Options::new().with_create(true); + /// assert_eq!(opts.create(), true); + /// ``` + #[inline] + + pub const fn create(&self) -> bool { + self.create + } + + /// Returns `true` if the file should be created if it does not exist and fail if it does. + /// + /// ## Examples + /// + /// ```rust + /// use orderwal::Options; + /// + /// let opts = Options::new().with_create_new(true); + /// assert_eq!(opts.create_new(), true); + /// ``` + #[inline] + + pub const fn create_new(&self) -> bool { + self.create_new + } + + /// Returns `true` if the memory map should be suitable for a process or thread stack. + /// + /// ## Examples + /// + /// ```rust + /// use orderwal::Options; + /// + /// let opts = Options::new().with_stack(true); + /// assert_eq!(opts.stack(), true); + /// ``` + #[inline] + pub const fn stack(&self) -> bool { + self.stack + } + + /// Returns the page bits of the memory map. + /// + /// ## Examples + /// + /// ```rust + /// use orderwal::Options; + /// + /// let opts = Options::new().with_huge(Some(8)); + /// assert_eq!(opts.huge(), Some(8)); + /// ``` + #[inline] + pub const fn huge(&self) -> Option { + self.huge + } + + /// Returns `true` if the memory map should populate (prefault) page tables for a mapping. + /// + /// ## Examples + /// + /// ```rust + /// use orderwal::Options; + /// + /// let opts = Options::new().with_populate(true); + /// assert_eq!(opts.populate(), true); + /// ``` + #[inline] + pub const fn populate(&self) -> bool { + self.populate + } +} + +pub(crate) trait ArenaOptionsExt { + fn merge(self, opts: &Options) -> Self; +} + +impl ArenaOptionsExt for super::ArenaOptions { + #[inline] + fn merge(self, opts: &Options) -> Self { + let new = self + .with_read(opts.read()) + .with_write(opts.write()) + .with_create(opts.create()) + .with_create_new(opts.create_new()) + .with_truncate(opts.truncate()) + .with_append(opts.append()) + .with_stack(opts.stack()) + .with_populate(opts.populate()) + .with_huge(opts.huge()); + + if let Some(cap) = opts.cap { + new.with_capacity(cap) + } else { + new + } + } } diff --git a/src/swmr/generic.rs b/src/swmr/generic.rs index dc0291bf..34817ba0 100644 --- a/src/swmr/generic.rs +++ b/src/swmr/generic.rs @@ -16,7 +16,7 @@ use dbutils::{ checksum::{BuildChecksumer, Checksumer, Crc32}, leb128::encoded_u64_varint_len, }; -use rarena_allocator::{either::Either, sync::Arena, Allocator, Memory, MmapOptions, OpenOptions}; +use rarena_allocator::{either::Either, sync::Arena, Allocator, Buffer}; use crate::{ arena_options, check, entry_size, diff --git a/src/swmr/generic/builder.rs b/src/swmr/generic/builder.rs index a3a47eba..f5d6029f 100644 --- a/src/swmr/generic/builder.rs +++ b/src/swmr/generic/builder.rs @@ -1,5 +1,7 @@ use std::path::{Path, PathBuf}; +use crate::options::ArenaOptionsExt; + use super::*; /// A write-ahead log builder. @@ -187,33 +189,6 @@ impl GenericBuilder { self.opts.sync_on_write() } - /// Returns the bits of the page size. - /// - /// Configures the anonymous memory map to be allocated using huge pages. - /// - /// This option corresponds to the `MAP_HUGETLB` flag on Linux. It has no effect on Windows. - /// - /// The size of the requested page can be specified in page bits. - /// If not provided, the system default is requested. - /// The requested length should be a multiple of this, or the mapping will fail. - /// - /// This option has no effect on file-backed memory maps. - /// - /// The default value is `None`. - /// - /// ## Example - /// - /// ```rust - /// use orderwal::swmr::GenericBuilder; - /// - /// let options = GenericBuilder::new().with_huge(64); - /// assert_eq!(options.huge(), Some(64)); - /// ``` - #[inline] - pub const fn huge(&self) -> Option { - self.opts.huge() - } - /// Sets the capacity of the WAL. /// /// This configuration will be ignored when using file-backed memory maps. @@ -266,71 +241,406 @@ impl GenericBuilder { self } - /// Returns the bits of the page size. + /// Sets the WAL to sync on write. /// - /// Configures the anonymous memory map to be allocated using huge pages. + /// The default value is `true`. /// - /// This option corresponds to the `MAP_HUGETLB` flag on Linux. It has no effect on Windows. + /// ## Example /// - /// The size of the requested page can be specified in page bits. - /// If not provided, the system default is requested. - /// The requested length should be a multiple of this, or the mapping will fail. + /// ```rust + /// use orderwal::swmr::GenericBuilder; /// - /// This option has no effect on file-backed memory maps. + /// let options = GenericBuilder::new().with_sync_on_write(false); + /// assert_eq!(options.sync_on_write(), false); + /// ``` + #[inline] + pub const fn with_sync_on_write(mut self, sync: bool) -> Self { + self.opts = self.opts.with_sync_on_write(sync); + self + } + + /// Sets the magic version. /// - /// The default value is `None`. + /// The default value is `0`. /// /// ## Example /// /// ```rust /// use orderwal::swmr::GenericBuilder; /// - /// let options = GenericBuilder::new().with_huge(64); - /// assert_eq!(options.huge(), Some(64)); + /// let options = GenericBuilder::new().with_magic_version(1); + /// assert_eq!(options.magic_version(), 1); /// ``` #[inline] - pub const fn with_huge(mut self, page_bits: u8) -> Self { - self.opts = self.opts.with_huge(page_bits); + pub const fn with_magic_version(mut self, version: u16) -> Self { + self.opts = self.opts.with_magic_version(version); self } +} - /// Sets the WAL to sync on write. +impl GenericBuilder { + /// Sets the option for read access. /// - /// The default value is `true`. + /// This option, when true, will indicate that the file should be + /// `read`-able if opened. /// - /// ## Example + /// ## Examples /// /// ```rust /// use orderwal::swmr::GenericBuilder; /// - /// let options = GenericBuilder::new().with_sync_on_write(false); - /// assert_eq!(options.sync_on_write(), false); + /// let opts = GenericBuilder::new().with_read(true); /// ``` #[inline] - pub const fn with_sync_on_write(mut self, sync: bool) -> Self { - self.opts = self.opts.with_sync_on_write(sync); + pub fn with_read(mut self, read: bool) -> Self { + self.opts.read = read; self } - /// Sets the magic version. + /// Sets the option for write access. /// - /// The default value is `0`. + /// This option, when true, will indicate that the file should be + /// `write`-able if opened. /// - /// ## Example + /// If the file already exists, any write calls on it will overwrite its + /// contents, without truncating it. + /// + /// ## Examples /// /// ```rust /// use orderwal::swmr::GenericBuilder; /// - /// let options = GenericBuilder::new().with_magic_version(1); - /// assert_eq!(options.magic_version(), 1); + /// let opts = GenericBuilder::new().with_write(true); /// ``` #[inline] - pub const fn with_magic_version(mut self, version: u16) -> Self { - self.opts = self.opts.with_magic_version(version); + pub fn with_write(mut self, write: bool) -> Self { + self.opts.write = write; + self + } + + /// Sets the option for the append mode. + /// + /// This option, when true, means that writes will append to a file instead + /// of overwriting previous contents. + /// Note that setting `.write(true).append(true)` has the same effect as + /// setting only `.append(true)`. + /// + /// For most filesystems, the operating system guarantees that all writes are + /// atomic: no writes get mangled because another process writes at the same + /// time. + /// + /// One maybe obvious note when using append-mode: make sure that all data + /// that belongs together is written to the file in one operation. This + /// can be done by concatenating strings before passing them to [`write()`], + /// or using a buffered writer (with a buffer of adequate size), + /// and calling [`flush()`] when the message is complete. + /// + /// If a file is opened with both read and append access, beware that after + /// opening, and after every write, the position for reading may be set at the + /// end of the file. So, before writing, save the current position (using + /// [seek]\([SeekFrom](std::io::SeekFrom)::[Current]\(opts))), and restore it before the next read. + /// + /// ## Note + /// + /// This function doesn't create the file if it doesn't exist. Use the + /// [`Options::with_create`] method to do so. + /// + /// [`write()`]: std::io::Write::write "io::Write::write" + /// [`flush()`]: std::io::Write::flush "io::Write::flush" + /// [seek]: std::io::Seek::seek "io::Seek::seek" + /// [Current]: std::io::SeekFrom::Current "io::SeekFrom::Current" + /// + /// ## Examples + /// + /// ```rust + /// use orderwal::swmr::GenericBuilder; + /// + /// let opts = GenericBuilder::new().with_append(true); + /// ``` + #[inline] + pub fn with_append(mut self, append: bool) -> Self { + self.opts.write = true; + self.opts.append = append; + self + } + + /// Sets the option for truncating a previous file. + /// + /// If a file is successfully opened with this option set it will truncate + /// the file to opts length if it already exists. + /// + /// The file must be opened with write access for truncate to work. + /// + /// ## Examples + /// + /// ```rust + /// use orderwal::swmr::GenericBuilder; + /// + /// let opts = GenericBuilder::new().with_write(true).with_truncate(true); + /// ``` + #[inline] + pub fn with_truncate(mut self, truncate: bool) -> Self { + self.opts.truncate = truncate; + self.opts.write = true; + self + } + + /// Sets the option to create a new file, or open it if it already exists. + /// If the file does not exist, it is created and set the lenght of the file to the given size. + /// + /// In order for the file to be created, [`Options::with_write`] or + /// [`Options::with_append`] access must be used. + /// + /// See also [`std::fs::write()`][std::fs::write] for a simple function to + /// create a file with some given data. + /// + /// ## Examples + /// + /// ```rust + /// use orderwal::swmr::GenericBuilder; + /// + /// let opts = GenericBuilder::new().with_write(true).with_create(true); + /// ``` + #[inline] + pub fn with_create(mut self, val: bool) -> Self { + self.opts.create = val; + self + } + + /// Sets the option to create a new file and set the file length to the given value, failing if it already exists. + /// + /// No file is allowed to exist at the target location, also no (dangling) symlink. In this + /// way, if the call succeeds, the file returned is guaranteed to be new. + /// + /// This option is useful because it is atomic. Otherwise between checking + /// whether a file exists and creating a new one, the file may have been + /// created by another process (a TOCTOU race condition / attack). + /// + /// If `.with_create_new(true)` is set, [`.with_create()`] and [`.with_truncate()`] are + /// ignored. + /// + /// The file must be opened with write or append access in order to create + /// a new file. + /// + /// [`.with_create()`]: GenericBuilder::with_create + /// [`.with_truncate()`]: GenericBuilder::with_truncate + /// + /// ## Examples + /// + /// ```rust + /// use orderwal::swmr::GenericBuilder; + /// + /// let opts = GenericBuilder::new() + /// .with_write(true) + /// .with_create_new(true); + /// ``` + #[inline] + pub fn with_create_new(mut self, val: bool) -> Self { + self.opts.create_new = val; + self + } + + /// Configures the anonymous memory map to be suitable for a process or thread stack. + /// + /// This option corresponds to the `MAP_STACK` flag on Linux. It has no effect on Windows. + /// + /// This option has no effect on file-backed memory maps and vec backed [`GenericOrderWal`]. + /// + /// ## Example + /// + /// ``` + /// use orderwal::swmr::GenericBuilder; + /// + /// let opts = GenericBuilder::new().with_stack(true); + /// ``` + #[inline] + pub fn with_stack(mut self, stack: bool) -> Self { + self.opts.stack = stack; + self + } + + /// Configures the anonymous memory map to be allocated using huge pages. + /// + /// This option corresponds to the `MAP_HUGETLB` flag on Linux. It has no effect on Windows. + /// + /// The size of the requested page can be specified in page bits. If not provided, the system + /// default is requested. The requested length should be a multiple of this, or the mapping + /// will fail. + /// + /// This option has no effect on file-backed memory maps and vec backed [`GenericOrderWal`]. + /// + /// ## Example + /// + /// ``` + /// use orderwal::swmr::GenericBuilder; + /// + /// let opts = GenericBuilder::new().with_huge(Some(8)); + /// ``` + #[inline] + pub fn with_huge(mut self, page_bits: Option) -> Self { + self.opts.huge = page_bits; + self + } + + /// Populate (prefault) page tables for a mapping. + /// + /// For a file mapping, this causes read-ahead on the file. This will help to reduce blocking on page faults later. + /// + /// This option corresponds to the `MAP_POPULATE` flag on Linux. It has no effect on Windows. + /// + /// This option has no effect on vec backed [`GenericOrderWal`]. + /// + /// ## Example + /// + /// ``` + /// use orderwal::swmr::GenericBuilder; + /// + /// let opts = GenericBuilder::new().with_populate(true); + /// ``` + #[inline] + pub fn with_populate(mut self, populate: bool) -> Self { + self.opts.populate = populate; self } } +impl GenericBuilder { + /// Returns `true` if the file should be opened with read access. + /// + /// ## Examples + /// + /// ```rust + /// use orderwal::swmr::GenericBuilder; + /// + /// let opts = GenericBuilder::new().with_read(true); + /// assert_eq!(opts.read(), true); + /// ``` + #[inline] + pub const fn read(&self) -> bool { + self.opts.read + } + + /// Returns `true` if the file should be opened with write access. + /// + /// ## Examples + /// + /// ```rust + /// use orderwal::swmr::GenericBuilder; + /// + /// let opts = GenericBuilder::new().with_write(true); + /// assert_eq!(opts.write(), true); + /// ``` + #[inline] + pub const fn write(&self) -> bool { + self.opts.write + } + + /// Returns `true` if the file should be opened with append access. + /// + /// ## Examples + /// + /// ```rust + /// use orderwal::swmr::GenericBuilder; + /// + /// let opts = GenericBuilder::new().with_append(true); + /// assert_eq!(opts.append(), true); + /// ``` + #[inline] + pub const fn append(&self) -> bool { + self.opts.append + } + + /// Returns `true` if the file should be opened with truncate access. + /// + /// ## Examples + /// + /// ```rust + /// use orderwal::swmr::GenericBuilder; + /// + /// let opts = GenericBuilder::new().with_truncate(true); + /// assert_eq!(opts.truncate(), true); + /// ``` + #[inline] + pub const fn truncate(&self) -> bool { + self.opts.truncate + } + + /// Returns `true` if the file should be created if it does not exist. + /// + /// ## Examples + /// + /// ```rust + /// use orderwal::swmr::GenericBuilder; + /// + /// let opts = GenericBuilder::new().with_create(true); + /// assert_eq!(opts.create(), true); + /// ``` + #[inline] + pub const fn create(&self) -> bool { + self.opts.create + } + + /// Returns `true` if the file should be created if it does not exist and fail if it does. + /// + /// ## Examples + /// + /// ```rust + /// use orderwal::swmr::GenericBuilder; + /// + /// let opts = GenericBuilder::new().with_create_new(true); + /// assert_eq!(opts.create_new(), true); + /// ``` + #[inline] + pub const fn create_new(&self) -> bool { + self.opts.create_new + } + + /// Returns `true` if the memory map should be suitable for a process or thread stack. + /// + /// ## Examples + /// + /// ```rust + /// use orderwal::swmr::GenericBuilder; + /// + /// let opts = GenericBuilder::new().with_stack(true); + /// assert_eq!(opts.stack(), true); + /// ``` + #[inline] + pub const fn stack(&self) -> bool { + self.opts.stack + } + + /// Returns the page bits of the memory map. + /// + /// ## Examples + /// + /// ```rust + /// use orderwal::swmr::GenericBuilder; + /// + /// let opts = GenericBuilder::new().with_huge(Some(8)); + /// assert_eq!(opts.huge(), Some(8)); + /// ``` + #[inline] + pub const fn huge(&self) -> Option { + self.opts.huge + } + + /// Returns `true` if the memory map should populate (prefault) page tables for a mapping. + /// + /// ## Examples + /// + /// ```rust + /// use orderwal::swmr::GenericBuilder; + /// + /// let opts = GenericBuilder::new().with_populate(true); + /// assert_eq!(opts.populate(), true); + /// ``` + #[inline] + pub const fn populate(&self) -> bool { + self.opts.populate + } +} + impl GenericBuilder { /// Creates a new in-memory write-ahead log backed by an aligned vec with the given capacity and options. /// @@ -368,7 +678,8 @@ impl GenericBuilder { let Self { opts, cks } = self; arena_options(opts.reserved()) - .map_anon(MmapOptions::new().len(opts.capacity())) + .merge(&opts) + .map_anon() .map_err(Into::into) .and_then(|arena| { GenericOrderWal::new_in(arena, opts, (), cks).map(GenericOrderWal::from_core) @@ -389,7 +700,7 @@ impl GenericBuilder { /// /// ```rust /// - /// use orderwal::{swmr::{GenericOrderWal, GenericBuilder, generic::*}, OpenOptions}; + /// use orderwal::swmr::{GenericOrderWal, GenericBuilder, generic::*}; /// # let dir = tempfile::tempdir().unwrap(); /// # let path = dir /// # .path() @@ -397,12 +708,12 @@ impl GenericBuilder { /// # /// # let mut wal = unsafe { /// # GenericBuilder::new() + /// # .with_capacity(1024) + /// # .with_create_new(true) + /// # .with_read(true) + /// # .with_write(true) /// # .map_mut::( /// # &path, - /// # OpenOptions::new() - /// # .create_new(Some(1024)) - /// # .write(true) - /// # .read(true), /// # ) /// # .unwrap() /// # }; @@ -434,7 +745,7 @@ impl GenericBuilder { /// ## Example /// /// ```rust - /// use orderwal::{swmr::{GenericOrderWal, GenericBuilder, generic::*}, OpenOptions}; + /// use orderwal::swmr::{GenericOrderWal, GenericBuilder, generic::*}; /// # let dir = tempfile::tempdir().unwrap(); /// # let path = dir /// # .path() @@ -442,12 +753,12 @@ impl GenericBuilder { /// # /// # let mut wal = unsafe { /// # GenericBuilder::new() - /// # .map_mut::( + /// # .with_capacity(1024) + /// # .with_create_new(true) + /// # .with_read(true) + /// # .with_write(true) + /// # .map_mut::( /// # &path, - /// # OpenOptions::new() - /// # .create_new(Some(1024)) - /// # .write(true) - /// # .read(true), /// # ) /// # .unwrap() /// # }; @@ -466,10 +777,11 @@ impl GenericBuilder { PB: FnOnce() -> Result, { let Self { cks, opts } = self; - let open_options = OpenOptions::default().read(true); arena_options(opts.reserved()) - .map_with_path_builder(path_builder, open_options, MmapOptions::new()) + .merge(&opts) + .with_read(true) + .map_with_path_builder(path_builder) .map_err(|e| e.map_right(Into::into)) .and_then(|arena| { GenericOrderWal::replay(arena, opts, true, (), cks) @@ -491,7 +803,7 @@ impl GenericBuilder { /// ## Example /// /// ```rust - /// use orderwal::{swmr::{GenericOrderWal, GenericBuilder, generic::*}, OpenOptions}; + /// use orderwal::swmr::{GenericOrderWal, GenericBuilder, generic::*}; /// /// # let dir = tempfile::tempdir().unwrap(); /// # let path = dir @@ -499,21 +811,19 @@ impl GenericBuilder { /// # .join("generic_wal_map_mut"); /// /// let mut wal = unsafe { - /// GenericBuilder::new().map_mut::( - /// &path, - /// OpenOptions::new() - /// .create_new(Some(1024)) - /// .write(true) - /// .read(true), - /// ) - /// .unwrap() + /// GenericBuilder::new() + /// .with_capacity(1024) + /// .with_create_new(true) + /// .with_read(true) + /// .with_write(true) + /// .map_mut::(&path) + /// .unwrap() /// }; /// ``` #[inline] pub unsafe fn map_mut>( self, path: P, - open_options: OpenOptions, ) -> Result, Error> where K: Type + Ord + 'static, @@ -521,7 +831,7 @@ impl GenericBuilder { V: 'static, { self - .map_mut_with_path_builder::(|| dummy_path_builder(path), open_options) + .map_mut_with_path_builder::(|| dummy_path_builder(path)) .map_err(|e| e.unwrap_right()) } @@ -538,27 +848,27 @@ impl GenericBuilder { /// ## Example /// /// ```rust - /// use orderwal::{swmr::{GenericOrderWal, GenericBuilder, generic::*}, OpenOptions}; + /// use orderwal::swmr::{GenericOrderWal, GenericBuilder, generic::*}; /// /// let dir = tempfile::tempdir().unwrap(); /// /// let mut wal = unsafe { - /// GenericBuilder::new().map_mut_with_path_builder::( - /// || { + /// GenericBuilder::new() + /// .with_create_new(true) + /// .with_write(true) + /// .with_read(true) + /// .with_capacity(1024) + /// .map_mut_with_path_builder::( + /// || { /// Ok(dir.path().join("generic_wal_map_mut_with_path_builder_and_checksumer")) - /// }, - /// OpenOptions::new() - /// .create_new(Some(1024)) - /// .write(true) - /// .read(true), - /// ) - /// .unwrap() + /// }, + /// ) + /// .unwrap() /// }; /// ``` pub unsafe fn map_mut_with_path_builder( self, path_builder: PB, - open_options: OpenOptions, ) -> Result, Either> where K: Type + Ord + 'static, @@ -570,7 +880,8 @@ impl GenericBuilder { let path = path_builder().map_err(Either::Left)?; let exist = path.exists(); let arena = arena_options(opts.reserved()) - .map_mut_with_path_builder(|| Ok(path), open_options, MmapOptions::new()) + .merge(&opts) + .map_mut_with_path_builder(|| Ok(path)) .map_err(|e| e.map_right(Into::into))?; if !exist { diff --git a/src/swmr/generic/tests/constructor.rs b/src/swmr/generic/tests/constructor.rs index 14633a20..617cf7de 100644 --- a/src/swmr/generic/tests/constructor.rs +++ b/src/swmr/generic/tests/constructor.rs @@ -161,13 +161,11 @@ fn construct_map_file() { unsafe { let mut wal = GenericBuilder::new() - .map_mut::( - &path, - OpenOptions::new() - .create_new(Some(MB)) - .write(true) - .read(true), - ) + .with_capacity(MB) + .with_create_new(true) + .with_read(true) + .with_write(true) + .map_mut::(&path) .unwrap(); let person = Person { id: 1, @@ -178,7 +176,6 @@ fn construct_map_file() { .insert(&person, &"My name is Alice!".to_string()) .unwrap(); assert_eq!(wal.get(&person).unwrap().value(), "My name is Alice!"); - assert_eq!(*wal.path().unwrap().as_ref(), path); } @@ -189,10 +186,11 @@ fn construct_map_file() { unsafe { let wal = GenericBuilder::new() - .map_mut::( - &path, - OpenOptions::new().create(Some(MB)).write(true).read(true), - ) + .with_capacity(MB) + .with_create(true) + .with_read(true) + .with_write(true) + .map_mut::(&path) .unwrap(); assert_eq!(wal.get(&pr).unwrap().value(), "My name is Alice!"); } @@ -239,13 +237,12 @@ fn construct_with_small_capacity_map_file() { .join("generic_wal_construct_with_small_capacity_map_file"); let wal = unsafe { - GenericBuilder::new().map_mut::( - &path, - OpenOptions::new() - .create_new(Some(1)) - .write(true) - .read(true), - ) + GenericBuilder::new() + .with_capacity(1) + .with_create_new(true) + .with_read(true) + .with_write(true) + .map_mut::(&path) }; assert!(wal.is_err()); @@ -291,13 +288,11 @@ fn zero_reserved_map_file() { let mut wal = unsafe { GenericBuilder::new() - .map_mut::( - &path, - OpenOptions::new() - .create_new(Some(MB)) - .write(true) - .read(true), - ) + .with_capacity(MB) + .with_create_new(true) + .with_read(true) + .with_write(true) + .map_mut::(&path) .unwrap() }; @@ -345,13 +340,11 @@ fn reserved_map_file() { let mut wal = unsafe { GenericBuilder::new() .with_reserved(4) - .map_mut::( - &path, - OpenOptions::new() - .create_new(Some(MB)) - .write(true) - .read(true), - ) + .with_capacity(MB) + .with_create_new(true) + .with_read(true) + .with_write(true) + .map_mut::(&path) .unwrap() }; diff --git a/src/swmr/generic/tests/get.rs b/src/swmr/generic/tests/get.rs index d454d7d1..b005a597 100644 --- a/src/swmr/generic/tests/get.rs +++ b/src/swmr/generic/tests/get.rs @@ -49,13 +49,11 @@ fn first_map_file() { let mut wal = unsafe { GenericBuilder::new() - .map_mut( - &path, - OpenOptions::new() - .create_new(Some(MB)) - .write(true) - .read(true), - ) + .with_capacity(MB) + .with_create_new(true) + .with_read(true) + .with_write(true) + .map_mut(&path) .unwrap() }; @@ -110,13 +108,11 @@ fn last_map_file() { let mut wal = unsafe { GenericBuilder::new() - .map_mut( - &path, - OpenOptions::new() - .create_new(Some(MB)) - .write(true) - .read(true), - ) + .with_capacity(MB) + .with_create_new(true) + .with_read(true) + .with_write(true) + .map_mut(&path) .unwrap() }; @@ -181,13 +177,11 @@ fn get_or_insert_map_file() { let mut wal = unsafe { GenericBuilder::new() - .map_mut( - &path, - OpenOptions::new() - .create_new(Some(MB)) - .write(true) - .read(true), - ) + .with_capacity(MB) + .with_create_new(true) + .with_read(true) + .with_write(true) + .map_mut(&path) .unwrap() }; @@ -253,13 +247,11 @@ fn get_or_insert_with_map_file() { let mut wal = unsafe { GenericBuilder::new() - .map_mut( - &path, - OpenOptions::new() - .create_new(Some(MB)) - .write(true) - .read(true), - ) + .with_capacity(MB) + .with_create_new(true) + .with_read(true) + .with_write(true) + .map_mut(&path) .unwrap() }; @@ -332,13 +324,11 @@ fn get_or_insert_key_with_value_bytes_map_file() { let mut wal = unsafe { GenericBuilder::new() - .map_mut( - &path, - OpenOptions::new() - .create_new(Some(MB)) - .write(true) - .read(true), - ) + .with_capacity(MB) + .with_create_new(true) + .with_read(true) + .with_write(true) + .map_mut(&path) .unwrap() }; @@ -410,13 +400,11 @@ fn get_or_insert_value_bytes_map_file() { let mut wal = unsafe { GenericBuilder::new() - .map_mut( - &path, - OpenOptions::new() - .create_new(Some(MB)) - .write(true) - .read(true), - ) + .with_capacity(MB) + .with_create_new(true) + .with_read(true) + .with_write(true) + .map_mut(&path) .unwrap() }; @@ -490,13 +478,11 @@ fn get_by_bytes_or_insert_with_map_file() { let mut wal = unsafe { GenericBuilder::new() - .map_mut( - &path, - OpenOptions::new() - .create_new(Some(MB)) - .write(true) - .read(true), - ) + .with_capacity(MB) + .with_create_new(true) + .with_read(true) + .with_write(true) + .map_mut(&path) .unwrap() }; @@ -575,13 +561,11 @@ fn get_by_bytes_or_insert_bytes_map_file() { let mut wal = unsafe { GenericBuilder::new() - .map_mut( - &path, - OpenOptions::new() - .create_new(Some(MB)) - .write(true) - .read(true), - ) + .with_capacity(MB) + .with_create_new(true) + .with_read(true) + .with_write(true) + .map_mut(&path) .unwrap() }; diff --git a/src/swmr/generic/tests/insert.rs b/src/swmr/generic/tests/insert.rs index 95d84b40..e7c611a5 100644 --- a/src/swmr/generic/tests/insert.rs +++ b/src/swmr/generic/tests/insert.rs @@ -39,13 +39,11 @@ fn insert_to_full_map_file() { unsafe { let mut wal = GenericBuilder::new() - .map_mut( - &path, - OpenOptions::new() - .create_new(Some(100)) - .write(true) - .read(true), - ) + .with_capacity(100) + .with_create_new(true) + .with_read(true) + .with_write(true) + .map_mut(&path) .unwrap(); insert_to_full(&mut wal); } @@ -101,13 +99,11 @@ fn insert_map_file() { let people = unsafe { let mut wal = GenericBuilder::new() - .map_mut( - &path, - OpenOptions::new() - .create_new(Some(MB)) - .write(true) - .read(true), - ) + .with_capacity(MB) + .with_create_new(true) + .with_read(true) + .with_write(true) + .map_mut(&path) .unwrap(); insert(&mut wal) }; @@ -196,13 +192,11 @@ fn insert_key_bytes_with_value_map_file() { let mut wal = unsafe { GenericBuilder::new() - .map_mut( - &path, - OpenOptions::new() - .create_new(Some(MB)) - .write(true) - .read(true), - ) + .with_capacity(MB) + .with_create_new(true) + .with_read(true) + .with_write(true) + .map_mut(&path) .unwrap() }; let people = insert_key_bytes_with_value(&mut wal); @@ -304,13 +298,11 @@ fn insert_key_with_value_bytes_map_file() { let mut wal = unsafe { GenericBuilder::new() - .map_mut( - &path, - OpenOptions::new() - .create_new(Some(MB)) - .write(true) - .read(true), - ) + .with_capacity(MB) + .with_create_new(true) + .with_read(true) + .with_write(true) + .map_mut(&path) .unwrap() }; @@ -386,13 +378,11 @@ fn insert_bytes_map_file() { let mut wal = unsafe { GenericBuilder::new() - .map_mut( - &path, - OpenOptions::new() - .create_new(Some(MB)) - .write(true) - .read(true), - ) + .with_capacity(MB) + .with_create_new(true) + .with_read(true) + .with_write(true) + .map_mut(&path) .unwrap() }; @@ -457,13 +447,11 @@ fn concurrent_basic_map_file() { let wal = unsafe { GenericBuilder::new() - .map_mut( - &path, - OpenOptions::new() - .create_new(Some(MB)) - .write(true) - .read(true), - ) + .with_capacity(MB) + .with_create_new(true) + .with_read(true) + .with_write(true) + .map_mut(&path) .unwrap() }; @@ -515,13 +503,11 @@ fn concurrent_one_key_map_file() { let wal = unsafe { GenericBuilder::new() - .map_mut( - &path, - OpenOptions::new() - .create_new(Some(MB)) - .write(true) - .read(true), - ) + .with_capacity(MB) + .with_create_new(true) + .with_read(true) + .with_write(true) + .map_mut(&path) .unwrap() }; @@ -622,13 +608,11 @@ fn test_insert_batch_map_file() { )); let mut map = unsafe { GenericBuilder::new() - .map_mut::( - &path, - OpenOptions::new() - .create_new(Some(MB)) - .write(true) - .read(true), - ) + .with_capacity(MB) + .with_create_new(true) + .with_read(true) + .with_write(true) + .map_mut::(&path) .unwrap() }; diff --git a/src/swmr/generic/tests/iters.rs b/src/swmr/generic/tests/iters.rs index 611e2a7b..b43ee917 100644 --- a/src/swmr/generic/tests/iters.rs +++ b/src/swmr/generic/tests/iters.rs @@ -55,13 +55,11 @@ fn iter_map_file() { let mut wal = unsafe { GenericBuilder::new() - .map_mut::( - &path, - OpenOptions::new() - .create_new(Some(MB)) - .write(true) - .read(true), - ) + .with_capacity(MB) + .with_create_new(true) + .with_read(true) + .with_write(true) + .map_mut::(&path) .unwrap() }; @@ -142,13 +140,11 @@ fn range_map_file() { let mut wal = unsafe { GenericBuilder::new() - .map_mut::( - &path, - OpenOptions::new() - .create_new(Some(MB)) - .write(true) - .read(true), - ) + .with_capacity(MB) + .with_create_new(true) + .with_read(true) + .with_write(true) + .map_mut::(&path) .unwrap() }; @@ -224,13 +220,11 @@ fn range_ref_map_file() { let mut wal = unsafe { GenericBuilder::new() - .map_mut( - &path, - OpenOptions::new() - .create_new(Some(MB)) - .write(true) - .read(true), - ) + .with_capacity(MB) + .with_create_new(true) + .with_read(true) + .with_write(true) + .map_mut(&path) .unwrap() }; diff --git a/src/tests.rs b/src/tests.rs index 2201c916..764e1857 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -23,14 +23,17 @@ macro_rules! common_unittests { fn test_insert_to_full_map_file() { let dir = ::tempfile::tempdir().unwrap(); $crate::tests::insert_to_full( - &mut unsafe { $crate::Builder::new().map_mut::<$wal, _>( - dir.path().join(concat!("test_", stringify!($prefix), "_insert_to_full_map_file")), - $crate::OpenOptions::new() - .create_new(Some(100)) - .write(true) - .read(true), - ) - .unwrap() }, + &mut unsafe { + $crate::Builder::new() + .with_capacity(100) + .with_create_new(true) + .with_read(true) + .with_write(true) + .map_mut::<$wal, _>( + dir.path().join(concat!("test_", stringify!($prefix), "_insert_to_full_map_file")), + ) + .unwrap() + }, ); } @@ -49,12 +52,8 @@ macro_rules! common_unittests { fn test_insert_map_file() { let dir = ::tempfile::tempdir().unwrap(); $crate::tests::insert( - &mut unsafe { $crate::Builder::new().map_mut::<$wal, _>( + &mut unsafe { $crate::Builder::new().with_create_new(true).with_read(true).with_write(true).with_capacity(MB as u32).map_mut::<$wal, _>( dir.path().join(concat!("test_", stringify!($prefix), "_insert_map_file")), - $crate::OpenOptions::new() - .create_new(Some(MB)) - .write(true) - .read(true), ) .unwrap() }, ); @@ -75,12 +74,9 @@ macro_rules! common_unittests { fn test_insert_with_key_builder_map_file() { let dir = ::tempfile::tempdir().unwrap(); $crate::tests::insert_with_key_builder( - &mut unsafe { $crate::Builder::new().map_mut::<$wal, _>( + &mut unsafe { $crate::Builder::new().with_create_new(true).with_read(true).with_write(true).with_capacity(MB as u32).map_mut::<$wal, _>( dir.path().join(concat!("test_", stringify!($prefix), "_insert_with_key_builder_map_file")), - $crate::OpenOptions::new() - .create_new(Some(MB)) - .write(true) - .read(true), + ) .unwrap() }, ); @@ -101,12 +97,9 @@ macro_rules! common_unittests { fn test_insert_with_value_builder_map_file() { let dir = ::tempfile::tempdir().unwrap(); $crate::tests::insert_with_value_builder( - &mut unsafe { $crate::Builder::new().map_mut::<$wal, _>( + &mut unsafe { $crate::Builder::new().with_create_new(true).with_read(true).with_write(true).with_capacity(MB as u32).map_mut::<$wal, _>( dir.path().join(concat!("test_", stringify!($prefix), "_insert_with_value_builder_map_file")), - $crate::OpenOptions::new() - .create_new(Some(MB)) - .write(true) - .read(true), + ) .unwrap() }, ); @@ -127,12 +120,9 @@ macro_rules! common_unittests { fn test_insert_with_builders_map_file() { let dir = ::tempfile::tempdir().unwrap(); $crate::tests::insert_with_builders( - &mut unsafe { $crate::Builder::new().map_mut::<$wal, _>( + &mut unsafe { $crate::Builder::new().with_create_new(true).with_read(true).with_write(true).with_capacity(MB as u32).map_mut::<$wal, _>( dir.path().join(concat!("test_", stringify!($prefix), "_insert_with_builders_map_file")), - $crate::OpenOptions::new() - .create_new(Some(MB)) - .write(true) - .read(true), + ) .unwrap() }, ); @@ -161,12 +151,9 @@ macro_rules! common_unittests { "_insert_batch_map_file" )); let mut map = unsafe { - $crate::Builder::new().map_mut::<$wal, _>( + $crate::Builder::new().with_create_new(true).with_read(true).with_write(true).with_capacity(MB as u32).map_mut::<$wal, _>( &path, - $crate::OpenOptions::new() - .create_new(Some(MB)) - .write(true) - .read(true), + ) .unwrap() }; @@ -202,12 +189,9 @@ macro_rules! common_unittests { "_insert_batch_with_key_builder_map_file" )); let mut map = unsafe { - $crate::Builder::new().map_mut::<$wal, _>( + $crate::Builder::new().with_create_new(true).with_read(true).with_write(true).with_capacity(MB as u32).map_mut::<$wal, _>( &path, - $crate::OpenOptions::new() - .create_new(Some(MB)) - .write(true) - .read(true), + ) .unwrap() }; @@ -241,12 +225,9 @@ macro_rules! common_unittests { "_insert_batch_with_value_builder_map_file" )); let mut map = unsafe { - $crate::Builder::new().map_mut::<$wal, _>( + $crate::Builder::new().with_create_new(true).with_read(true).with_write(true).with_capacity(MB as u32).map_mut::<$wal, _>( &path, - $crate::OpenOptions::new() - .create_new(Some(MB)) - .write(true) - .read(true), + ) .unwrap() }; @@ -280,12 +261,9 @@ macro_rules! common_unittests { "_insert_batch_with_builders_map_file" )); let mut map = unsafe { - $crate::Builder::new().map_mut::<$wal, _>( + $crate::Builder::new().with_create_new(true).with_read(true).with_write(true).with_capacity(MB as u32).map_mut::<$wal, _>( &path, - $crate::OpenOptions::new() - .create_new(Some(MB)) - .write(true) - .read(true), + ) .unwrap() }; @@ -317,12 +295,9 @@ macro_rules! common_unittests { fn test_iter_map_file() { let dir = ::tempfile::tempdir().unwrap(); $crate::tests::iter( - &mut unsafe { $crate::Builder::new().map_mut::<$wal, _>( + &mut unsafe { $crate::Builder::new().with_create_new(true).with_read(true).with_write(true).with_capacity(MB as u32).map_mut::<$wal, _>( dir.path().join(concat!("test_", stringify!($prefix), "_iter_map_file")), - $crate::OpenOptions::new() - .create_new(Some(MB)) - .write(true) - .read(true), + ) .unwrap() }, ); @@ -343,12 +318,9 @@ macro_rules! common_unittests { fn test_range_map_file() { let dir = ::tempfile::tempdir().unwrap(); $crate::tests::range( - &mut unsafe { $crate::Builder::new().map_mut::<$wal, _>( + &mut unsafe { $crate::Builder::new().with_create_new(true).with_read(true).with_write(true).with_capacity(MB as u32).map_mut::<$wal, _>( dir.path().join(concat!("test_", stringify!($prefix), "_range_map_file")), - $crate::OpenOptions::new() - .create_new(Some(MB)) - .write(true) - .read(true), + ) .unwrap() }, ); @@ -369,12 +341,9 @@ macro_rules! common_unittests { fn test_keys_map_file() { let dir = ::tempfile::tempdir().unwrap(); $crate::tests::keys( - &mut unsafe { $crate::Builder::new().map_mut::<$wal, _>( + &mut unsafe { $crate::Builder::new().with_create_new(true).with_read(true).with_write(true).with_capacity(MB as u32).map_mut::<$wal, _>( dir.path().join(concat!("test_", stringify!($prefix), "_keys_map_file")), - $crate::OpenOptions::new() - .create_new(Some(MB)) - .write(true) - .read(true), + ) .unwrap() }, ); @@ -395,12 +364,9 @@ macro_rules! common_unittests { fn test_values_map_file() { let dir = ::tempfile::tempdir().unwrap(); $crate::tests::values( - &mut unsafe { $crate::Builder::new().map_mut::<$wal, _>( + &mut unsafe { $crate::Builder::new().with_create_new(true).with_read(true).with_write(true).with_capacity(MB as u32).map_mut::<$wal, _>( dir.path().join(concat!("test_", stringify!($prefix), "_values_map_file")), - $crate::OpenOptions::new() - .create_new(Some(MB)) - .write(true) - .read(true), + ) .unwrap() }, ); @@ -421,12 +387,9 @@ macro_rules! common_unittests { fn test_range_keys_map_file() { let dir = ::tempfile::tempdir().unwrap(); $crate::tests::range_keys( - &mut unsafe { $crate::Builder::new().map_mut::<$wal, _>( + &mut unsafe { $crate::Builder::new().with_create_new(true).with_read(true).with_write(true).with_capacity(MB as u32).map_mut::<$wal, _>( dir.path().join(concat!("test_", stringify!($prefix), "_range_keys_map_file")), - $crate::OpenOptions::new() - .create_new(Some(MB)) - .write(true) - .read(true), + ) .unwrap() }, ); @@ -447,12 +410,9 @@ macro_rules! common_unittests { fn test_range_values_map_file() { let dir = ::tempfile::tempdir().unwrap(); $crate::tests::range_values( - &mut unsafe { $crate::Builder::new().map_mut::<$wal, _>( + &mut unsafe { $crate::Builder::new().with_create_new(true).with_read(true).with_write(true).with_capacity(MB as u32).map_mut::<$wal, _>( dir.path().join(concat!("test", stringify!($prefix), "_range_values_map_file")), - $crate::OpenOptions::new() - .create_new(Some(MB)) - .write(true) - .read(true), + ) .unwrap() }, ); @@ -476,12 +436,9 @@ macro_rules! common_unittests { fn test_first_map_file() { let dir = ::tempfile::tempdir().unwrap(); $crate::tests::first( - &mut unsafe { $crate::Builder::new().map_mut::<$wal, _>( + &mut unsafe { $crate::Builder::new().with_create_new(true).with_read(true).with_write(true).with_capacity(MB as u32).map_mut::<$wal, _>( dir.path().join(concat!("test_", stringify!($prefix), "_first_map_file")), - $crate::OpenOptions::new() - .create_new(Some(MB)) - .write(true) - .read(true), + ) .unwrap() }, ); @@ -502,12 +459,9 @@ macro_rules! common_unittests { fn test_last_map_file() { let dir = ::tempfile::tempdir().unwrap(); $crate::tests::last( - &mut unsafe { $crate::Builder::new().map_mut::<$wal, _>( + &mut unsafe { $crate::Builder::new().with_create_new(true).with_read(true).with_write(true).with_capacity(MB as u32).map_mut::<$wal, _>( dir.path().join(concat!("test_", stringify!($prefix), "_last_map_file")), - $crate::OpenOptions::new() - .create_new(Some(MB)) - .write(true) - .read(true), + ) .unwrap() }, ); @@ -528,12 +482,8 @@ macro_rules! common_unittests { fn test_get_or_insert_map_file() { let dir = ::tempfile::tempdir().unwrap(); - let mut wal = unsafe { $crate::Builder::new().map_mut::<$wal, _>( + let mut wal = unsafe { $crate::Builder::new().with_create_new(true).with_read(true).with_write(true).with_capacity(MB as u32).map_mut::<$wal, _>( dir.path().join(concat!("test_", stringify!($prefix), "_get_or_insert_map_file")), - $crate::OpenOptions::new() - .create_new(Some(MB)) - .write(true) - .read(true), ) .unwrap() }; @@ -559,12 +509,9 @@ macro_rules! common_unittests { fn test_get_or_insert_with_value_builder_map_file() { let dir = ::tempfile::tempdir().unwrap(); let path = dir.path().join(concat!("test_", stringify!($prefix), "_get_or_insert_with_value_builder_map_file")); - let mut wal = unsafe { $crate::Builder::new().map_mut::<$wal, _>( + let mut wal = unsafe { $crate::Builder::new().with_create_new(true).with_read(true).with_write(true).with_capacity(MB as u32).map_mut::<$wal, _>( &path, - $crate::OpenOptions::new() - .create_new(Some(MB)) - .write(true) - .read(true), + ) .unwrap() }; $crate::tests::get_or_insert_with_value_builder( @@ -626,12 +573,9 @@ macro_rules! common_unittests { fn test_zero_reserved_map_file() { let dir = ::tempfile::tempdir().unwrap(); $crate::tests::zero_reserved( - &mut unsafe { $crate::Builder::new().map_mut::<$wal, _>( + &mut unsafe { $crate::Builder::new().with_create_new(true).with_read(true).with_write(true).with_capacity(MB as u32).map_mut::<$wal, _>( dir.path().join(concat!("test_", stringify!($prefix), "_zero_reserved_map_file")), - $crate::OpenOptions::new() - .create_new(Some(MB)) - .write(true) - .read(true), + ) .unwrap() }, ); @@ -652,12 +596,9 @@ macro_rules! common_unittests { fn test_reserved_map_file() { let dir = ::tempfile::tempdir().unwrap(); $crate::tests::reserved( - &mut unsafe { Builder::new().with_reserved(4).map_mut::<$wal, _>( + &mut unsafe { Builder::new().with_reserved(4).with_capacity(MB).with_create_new(true).with_write(true).with_read(true).map_mut::<$wal, _>( dir.path().join(concat!("test_", stringify!($prefix), "_reserved_map_file")), - $crate::OpenOptions::new() - .create_new(Some(MB)) - .write(true) - .read(true), + ) .unwrap() }, ); @@ -691,13 +632,11 @@ pub(crate) fn construct_map_file>(prefix: &str) { unsafe { let mut wal = Builder::new() - .map_mut::( - &path, - OpenOptions::new() - .create_new(Some(MB as u32)) - .write(true) - .read(true), - ) + .with_capacity(MB as u32) + .with_create_new(true) + .with_read(true) + .with_write(true) + .map_mut::(&path) .unwrap(); let wal = &mut wal; @@ -707,13 +646,11 @@ pub(crate) fn construct_map_file>(prefix: &str) { unsafe { let wal = Builder::new() - .map_mut::( - &path, - OpenOptions::new() - .create(Some(MB as u32)) - .write(true) - .read(true), - ) + .with_capacity(MB as u32) + .with_create(true) + .with_read(true) + .with_write(true) + .map_mut::(&path) .unwrap(); assert_eq!(wal.get(b"key1").unwrap(), b"value1"); @@ -757,13 +694,12 @@ pub(crate) fn construct_with_small_capacity_map_file>(pref .join(format!("{prefix}_construct_with_small_capacity_map_file")); let wal = unsafe { - Builder::new().map_mut::( - &path, - OpenOptions::new() - .create_new(Some(1)) - .write(true) - .read(true), - ) + Builder::new() + .with_capacity(1) + .with_create_new(true) + .with_write(true) + .with_read(true) + .map_mut::(&path) }; assert!(wal.is_err()); diff --git a/src/utils.rs b/src/utils.rs index b08c761e..fa043a32 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -38,8 +38,6 @@ pub(crate) const fn arena_options(reserved: u32) -> ArenaOptions { .with_magic_version(CURRENT_VERSION) .with_freelist(Freelist::None) .with_reserved((HEADER_SIZE + reserved as usize) as u32) - // clear capacity - .with_capacity(0) .with_unify(true) }