feat(mmap): new feature for mmap-based optimization

This commit is contained in:
Michal Trybus 2023-05-17 19:11:31 +02:00
parent 81bc84b33d
commit ba036ab92a
2 changed files with 44 additions and 38 deletions

View File

@ -16,7 +16,7 @@ digest = "0.10.6"
either = "1.6.1" either = "1.6.1"
futures = "0.3.17" futures = "0.3.17"
hex = "0.4.3" hex = "0.4.3"
memmap2 = "0.5.8" memmap2 = { version = "0.5.8", optional = true }
miette = "5.7.0" miette = "5.7.0"
reflink = "0.1.3" reflink = "0.1.3"
serde = "1.0.130" serde = "1.0.130"
@ -53,6 +53,7 @@ name = "benchmarks"
harness = false harness = false
[features] [features]
default = ["async-std"] default = ["async-std", "mmap"]
mmap = ["memmap2"]
link_to = [] link_to = []
tokio-runtime = ["tokio", "tokio-stream"] tokio-runtime = ["tokio", "tokio-stream"]

View File

@ -6,6 +6,7 @@ use std::sync::Mutex;
use std::task::{Context, Poll}; use std::task::{Context, Poll};
use futures::prelude::*; use futures::prelude::*;
#[cfg(feature = "mmap")]
use memmap2::MmapMut; use memmap2::MmapMut;
use ssri::{Algorithm, Integrity, IntegrityOpts}; use ssri::{Algorithm, Integrity, IntegrityOpts};
use tempfile::NamedTempFile; use tempfile::NamedTempFile;
@ -14,8 +15,23 @@ use crate::async_lib::{AsyncWrite, JoinHandle};
use crate::content::path; use crate::content::path;
use crate::errors::{IoErrorExt, Result}; use crate::errors::{IoErrorExt, Result};
#[cfg(feature = "mmap")]
pub const MAX_MMAP_SIZE: usize = 1024 * 1024; pub const MAX_MMAP_SIZE: usize = 1024 * 1024;
#[cfg(not(feature = "mmap"))]
struct MmapMut;
#[cfg(not(feature = "mmap"))]
impl MmapMut {
fn flush_async(&self) -> std::io::Result<()> {
panic!()
}
fn copy_from_slice(&self, _: &[u8]) {
panic!()
}
}
pub struct Writer { pub struct Writer {
cache: PathBuf, cache: PathBuf,
builder: IntegrityOpts, builder: IntegrityOpts,
@ -44,24 +60,7 @@ impl Writer {
tmp_path_clone.display() tmp_path_clone.display()
) )
})?; })?;
let mmap = if let Some(size) = size { let mmap = make_mmap(&mut tmpfile, size)?;
if size <= MAX_MMAP_SIZE {
tmpfile
.as_file_mut()
.set_len(size as u64)
.with_context(|| {
format!(
"Failed to configure file length for temp file at {}",
tmpfile.path().display()
)
})?;
unsafe { MmapMut::map_mut(tmpfile.as_file()).ok() }
} else {
None
}
} else {
None
};
Ok(Writer { Ok(Writer {
cache: cache_path, cache: cache_path,
builder: IntegrityOpts::new().algorithm(algo), builder: IntegrityOpts::new().algorithm(algo),
@ -162,24 +161,7 @@ impl AsyncWriter {
) )
})?; })?;
let mut tmpfile = crate::async_lib::create_named_tempfile(tmp_path).await?; let mut tmpfile = crate::async_lib::create_named_tempfile(tmp_path).await?;
let mmap = if let Some(size) = size { let mmap = make_mmap(&mut tmpfile, size)?;
if size <= MAX_MMAP_SIZE {
tmpfile
.as_file_mut()
.set_len(size as u64)
.with_context(|| {
format!(
"Failed to configure file length for temp file at {}",
tmpfile.path().display()
)
})?;
unsafe { MmapMut::map_mut(tmpfile.as_file()).ok() }
} else {
None
}
} else {
None
};
Ok(AsyncWriter(Mutex::new(State::Idle(Some(Inner { Ok(AsyncWriter(Mutex::new(State::Idle(Some(Inner {
cache: cache_path, cache: cache_path,
builder: IntegrityOpts::new().algorithm(algo), builder: IntegrityOpts::new().algorithm(algo),
@ -428,6 +410,29 @@ impl AsyncWriter {
} }
} }
#[cfg(feature = "mmap")]
fn make_mmap(tmpfile: &mut NamedTempFile, size: Option<usize>) -> Result<Option<MmapMut>> {
if let Some(size @ 0..=MAX_MMAP_SIZE) = size {
tmpfile
.as_file_mut()
.set_len(size as u64)
.with_context(|| {
format!(
"Failed to configure file length for temp file at {}",
tmpfile.path().display()
)
})?;
Ok(unsafe { MmapMut::map_mut(tmpfile.as_file()).ok() })
} else {
Ok(None)
}
}
#[cfg(not(feature = "mmap"))]
fn make_mmap(_: &mut NamedTempFile, _: Option<usize>) -> Result<Option<MmapMut>> {
Ok(None)
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;