wasmer/lib/runtime/src/cache.rs

114 lines
4.0 KiB
Rust
Raw Normal View History

use crate::Module;
use memmap::Mmap;
use std::{
fs::{create_dir_all, File},
io::{self, Write},
path::PathBuf,
};
2019-03-19 00:40:36 +00:00
use wasmer_runtime_core::cache::{Error as CacheError};
pub use wasmer_runtime_core::cache::{Artifact, Cache, WasmHash, cache_versioned_sub_directory};
2019-02-21 22:00:33 +00:00
/// Representation of a directory that contains compiled wasm artifacts.
///
/// The `FileSystemCache` type implements the [`Cache`] trait, which allows it to be used
/// generically when some sort of cache is required.
///
/// [`Cache`]: trait.Cache.html
///
/// # Usage:
///
/// ```rust
2019-02-22 19:42:30 +00:00
/// use wasmer_runtime::cache::{Cache, FileSystemCache, WasmHash};
2019-02-21 22:00:33 +00:00
///
/// # use wasmer_runtime::{Module, error::CacheError};
2019-02-22 19:42:30 +00:00
/// fn store_module(module: Module) -> Result<Module, CacheError> {
2019-02-21 22:00:33 +00:00
/// // Create a new file system cache.
/// // This is unsafe because we can't ensure that the artifact wasn't
/// // corrupted or tampered with.
/// let mut fs_cache = unsafe { FileSystemCache::new("some/directory/goes/here")? };
2019-02-22 20:00:30 +00:00
/// // Compute a key for a given WebAssembly binary
/// let key = WasmHash::generate(&[]);
2019-02-22 19:42:30 +00:00
/// // Store a module into the cache given a key
2019-02-22 20:06:22 +00:00
/// fs_cache.store(key, module.clone())?;
2019-02-22 20:17:49 +00:00
/// Ok(module)
2019-02-21 22:00:33 +00:00
/// }
/// ```
pub struct FileSystemCache {
2019-02-21 19:47:28 +00:00
path: PathBuf,
2019-03-19 00:27:23 +00:00
versioned_sub_directory: String,
2019-02-21 19:47:28 +00:00
}
2019-02-21 22:00:33 +00:00
impl FileSystemCache {
/// Construct a new `FileSystemCache` around the specified directory.
2019-03-19 00:27:23 +00:00
/// The contents of the cache are stored in sub-versioned directories.
2019-02-21 22:00:33 +00:00
///
/// # Note:
/// This method is unsafe because there's no way to ensure the artifacts
/// stored in this cache haven't been corrupted or tampered with.
pub unsafe fn new<P: Into<PathBuf>>(path: P) -> io::Result<Self> {
2019-02-21 19:47:28 +00:00
let path: PathBuf = path.into();
2019-03-19 00:27:23 +00:00
let versioned_sub_directory = cache_versioned_sub_directory();
2019-02-21 19:47:28 +00:00
if path.exists() {
let metadata = path.metadata()?;
if metadata.is_dir() {
if !metadata.permissions().readonly() {
2019-03-19 00:27:23 +00:00
Ok(Self { path, versioned_sub_directory })
2019-02-21 19:47:28 +00:00
} else {
// This directory is readonly.
Err(io::Error::new(
io::ErrorKind::PermissionDenied,
format!("the supplied path is readonly: {}", path.display()),
))
}
} else {
// This path points to a file.
Err(io::Error::new(
io::ErrorKind::PermissionDenied,
format!(
"the supplied path already points to a file: {}",
path.display()
),
))
}
} else {
// Create the directory and any parent directories if they don't yet exist.
create_dir_all(&path)?;
2019-03-19 00:27:23 +00:00
Ok(Self { path, versioned_sub_directory })
2019-02-21 19:47:28 +00:00
}
}
}
2019-02-21 22:00:33 +00:00
impl Cache for FileSystemCache {
2019-02-21 19:47:28 +00:00
type LoadError = CacheError;
type StoreError = CacheError;
2019-02-21 22:00:33 +00:00
fn load(&self, key: WasmHash) -> Result<Module, CacheError> {
2019-02-21 19:47:28 +00:00
let filename = key.encode();
let mut new_path_buf = self.path.clone();
2019-03-19 00:27:23 +00:00
new_path_buf.push(&self.versioned_sub_directory);
2019-02-21 19:47:28 +00:00
new_path_buf.push(filename);
let file = File::open(new_path_buf)?;
let mmap = unsafe { Mmap::map(&file)? };
2019-02-21 19:47:28 +00:00
let serialized_cache = Artifact::deserialize(&mmap[..])?;
2019-02-21 22:00:33 +00:00
unsafe { wasmer_runtime_core::load_cache_with(serialized_cache, super::default_compiler()) }
2019-02-21 19:47:28 +00:00
}
2019-02-22 19:42:30 +00:00
fn store(&mut self, key: WasmHash, module: Module) -> Result<(), CacheError> {
2019-02-21 19:47:28 +00:00
let filename = key.encode();
let mut new_path_buf = self.path.clone();
2019-03-19 00:27:23 +00:00
new_path_buf.push(&self.versioned_sub_directory);
2019-02-21 19:47:28 +00:00
new_path_buf.push(filename);
let serialized_cache = module.cache()?;
let buffer = serialized_cache.serialize()?;
let mut file = File::create(new_path_buf)?;
2019-02-22 01:11:28 +00:00
file.write_all(&buffer)?;
2019-02-22 19:42:30 +00:00
Ok(())
2019-02-21 19:47:28 +00:00
}
}