Remove all global state from the caching system (#863)
* Remove all global state from the caching system This commit is a continuation of an effort to remove usages of `lazy_static!` and similar global state macros which can otherwise be accomodated with passing objects around. Previously there was a global cache system initialized per-process, but it was initialized in a bit of a roundabout way and wasn't actually reachable from the `wasmtime` crate itself. The changes here remove all global state, refactor many of the internals in the cache system, and makes configuration possible through the `wasmtime` crate. Specifically some changes here are: * Usage of `lazy_static!` and many `static` items in the cache module have all been removed. * Global `cache_config()`, `worker()`, and `init()` functions have all been removed. Instead a `CacheConfig` is a "root object" which internally owns its worker and passing around the `CacheConfig` is required for cache usage. * The `wasmtime::Config` structure has grown options to load and parse cache files at runtime. Currently only loading files is supported, although we can likely eventually support programmatically configuring APIs as well. * Usage of the `spin` crate has been removed and the dependency is removed. * The internal `errors` field of `CacheConfig` is removed, instead changing all relevant methods to return a `Result<()>` instead of storing errors internally. * Tests have all been updated with the new interfaces and APIs. Functionally no real change is intended here. Usage of the `wasmtime` CLI, for example, should still enable the cache by default. * Fix lightbeam compilation
This commit is contained in:
1
Cargo.lock
generated
1
Cargo.lock
generated
@@ -1980,7 +1980,6 @@ dependencies = [
|
|||||||
"rayon",
|
"rayon",
|
||||||
"serde",
|
"serde",
|
||||||
"sha2",
|
"sha2",
|
||||||
"spin",
|
|
||||||
"target-lexicon",
|
"target-lexicon",
|
||||||
"tempfile",
|
"tempfile",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
use std::path::Path;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use wasmtime_environ::settings::{self, Configurable};
|
use wasmtime_environ::settings::{self, Configurable};
|
||||||
|
use wasmtime_environ::CacheConfig;
|
||||||
use wasmtime_jit::{native, CompilationStrategy, Compiler, Features};
|
use wasmtime_jit::{native, CompilationStrategy, Compiler, Features};
|
||||||
|
|
||||||
// Runtime Environment
|
// Runtime Environment
|
||||||
@@ -21,6 +23,7 @@ pub struct Config {
|
|||||||
pub(crate) features: Features,
|
pub(crate) features: Features,
|
||||||
pub(crate) debug_info: bool,
|
pub(crate) debug_info: bool,
|
||||||
pub(crate) strategy: CompilationStrategy,
|
pub(crate) strategy: CompilationStrategy,
|
||||||
|
pub(crate) cache_config: CacheConfig,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Config {
|
impl Config {
|
||||||
@@ -45,6 +48,7 @@ impl Config {
|
|||||||
features: Default::default(),
|
features: Default::default(),
|
||||||
flags,
|
flags,
|
||||||
strategy: CompilationStrategy::Auto,
|
strategy: CompilationStrategy::Auto,
|
||||||
|
cache_config: CacheConfig::new_cache_disabled(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -221,6 +225,49 @@ impl Config {
|
|||||||
.expect("should be valid flag");
|
.expect("should be valid flag");
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Loads cache configuration specified at `path`.
|
||||||
|
///
|
||||||
|
/// This method will read the file specified by `path` on the filesystem and
|
||||||
|
/// attempt to load cache configuration from it. This method can also fail
|
||||||
|
/// due to I/O errors, misconfiguration, syntax errors, etc. For expected
|
||||||
|
/// syntax in the configuration file see the [documentation online][docs].
|
||||||
|
///
|
||||||
|
/// By default cache configuration is not enabled or loaded.
|
||||||
|
///
|
||||||
|
/// # Errors
|
||||||
|
///
|
||||||
|
/// This method can fail due to any error that happens when loading the file
|
||||||
|
/// pointed to by `path` and attempting to load the cache configuration.
|
||||||
|
///
|
||||||
|
/// [docs]: https://bytecodealliance.github.io/wasmtime/cli-cache.html
|
||||||
|
pub fn cache_config_load(&mut self, path: impl AsRef<Path>) -> Result<&mut Self> {
|
||||||
|
self.cache_config = wasmtime_environ::CacheConfig::from_file(Some(path.as_ref()))?;
|
||||||
|
Ok(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Loads cache configuration from the system default path.
|
||||||
|
///
|
||||||
|
/// This commit is the same as [`Config::cache_config_load`] except that it
|
||||||
|
/// does not take a path argument and instead loads the default
|
||||||
|
/// configuration present on the system. This is located, for example, on
|
||||||
|
/// Unix at `$HOME/.config/wasmtime/config.toml` and is typically created
|
||||||
|
/// with the `wasmtime config new` command.
|
||||||
|
///
|
||||||
|
/// By default cache configuration is not enabled or loaded.
|
||||||
|
///
|
||||||
|
/// # Errors
|
||||||
|
///
|
||||||
|
/// This method can fail due to any error that happens when loading the
|
||||||
|
/// default system configuration. Note that it is not an error if the
|
||||||
|
/// default config file does not exist, in which case the default settings
|
||||||
|
/// for an enabled cache are applied.
|
||||||
|
///
|
||||||
|
/// [docs]: https://bytecodealliance.github.io/wasmtime/cli-cache.html
|
||||||
|
pub fn cache_config_load_default(&mut self) -> Result<&mut Self> {
|
||||||
|
self.cache_config = wasmtime_environ::CacheConfig::from_file(None)?;
|
||||||
|
Ok(self)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Config {
|
impl Default for Config {
|
||||||
@@ -364,7 +411,11 @@ impl Store {
|
|||||||
/// Creates a new store to be associated with the given [`Engine`].
|
/// Creates a new store to be associated with the given [`Engine`].
|
||||||
pub fn new(engine: &Engine) -> Store {
|
pub fn new(engine: &Engine) -> Store {
|
||||||
let isa = native::builder().finish(settings::Flags::new(engine.config.flags.clone()));
|
let isa = native::builder().finish(settings::Flags::new(engine.config.flags.clone()));
|
||||||
let compiler = Compiler::new(isa, engine.config.strategy);
|
let compiler = Compiler::new(
|
||||||
|
isa,
|
||||||
|
engine.config.strategy,
|
||||||
|
engine.config.cache_config.clone(),
|
||||||
|
);
|
||||||
Store {
|
Store {
|
||||||
inner: Rc::new(StoreInner {
|
inner: Rc::new(StoreInner {
|
||||||
engine: engine.clone(),
|
engine: engine.clone(),
|
||||||
|
|||||||
@@ -27,7 +27,6 @@ base64 = "0.11.0"
|
|||||||
serde = { version = "1.0.94", features = ["derive"] }
|
serde = { version = "1.0.94", features = ["derive"] }
|
||||||
bincode = "1.1.4"
|
bincode = "1.1.4"
|
||||||
lazy_static = "1.3.0"
|
lazy_static = "1.3.0"
|
||||||
spin = "0.5.0"
|
|
||||||
log = { version = "0.4.8", default-features = false }
|
log = { version = "0.4.8", default-features = false }
|
||||||
zstd = "0.5"
|
zstd = "0.5"
|
||||||
toml = "0.5.5"
|
toml = "0.5.5"
|
||||||
|
|||||||
@@ -18,9 +18,8 @@ use std::path::{Path, PathBuf};
|
|||||||
mod config;
|
mod config;
|
||||||
mod worker;
|
mod worker;
|
||||||
|
|
||||||
use config::{cache_config, CacheConfig};
|
pub use config::{create_new_config, CacheConfig};
|
||||||
pub use config::{create_new_config, init};
|
use worker::Worker;
|
||||||
use worker::{worker, Worker};
|
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
static ref SELF_MTIME: String = {
|
static ref SELF_MTIME: String = {
|
||||||
@@ -48,12 +47,11 @@ lazy_static! {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ModuleCacheEntry<'config, 'worker>(Option<ModuleCacheEntryInner<'config, 'worker>>);
|
pub struct ModuleCacheEntry<'config>(Option<ModuleCacheEntryInner<'config>>);
|
||||||
|
|
||||||
struct ModuleCacheEntryInner<'config, 'worker> {
|
struct ModuleCacheEntryInner<'config> {
|
||||||
mod_cache_path: PathBuf,
|
mod_cache_path: PathBuf,
|
||||||
cache_config: &'config CacheConfig,
|
cache_config: &'config CacheConfig,
|
||||||
worker: &'worker Worker,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Cached compilation data of a Wasm module.
|
/// Cached compilation data of a Wasm module.
|
||||||
@@ -79,15 +77,15 @@ pub type ModuleCacheDataTupleType = (
|
|||||||
|
|
||||||
struct Sha256Hasher(Sha256);
|
struct Sha256Hasher(Sha256);
|
||||||
|
|
||||||
impl<'config, 'worker> ModuleCacheEntry<'config, 'worker> {
|
impl<'config> ModuleCacheEntry<'config> {
|
||||||
pub fn new<'data>(
|
pub fn new<'data>(
|
||||||
module: &Module,
|
module: &Module,
|
||||||
function_body_inputs: &PrimaryMap<DefinedFuncIndex, FunctionBodyData<'data>>,
|
function_body_inputs: &PrimaryMap<DefinedFuncIndex, FunctionBodyData<'data>>,
|
||||||
isa: &dyn isa::TargetIsa,
|
isa: &dyn isa::TargetIsa,
|
||||||
compiler_name: &str,
|
compiler_name: &str,
|
||||||
generate_debug_info: bool,
|
generate_debug_info: bool,
|
||||||
|
cache_config: &'config CacheConfig,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let cache_config = cache_config();
|
|
||||||
if cache_config.enabled() {
|
if cache_config.enabled() {
|
||||||
Self(Some(ModuleCacheEntryInner::new(
|
Self(Some(ModuleCacheEntryInner::new(
|
||||||
module,
|
module,
|
||||||
@@ -96,7 +94,6 @@ impl<'config, 'worker> ModuleCacheEntry<'config, 'worker> {
|
|||||||
compiler_name,
|
compiler_name,
|
||||||
generate_debug_info,
|
generate_debug_info,
|
||||||
cache_config,
|
cache_config,
|
||||||
worker(),
|
|
||||||
)))
|
)))
|
||||||
} else {
|
} else {
|
||||||
Self(None)
|
Self(None)
|
||||||
@@ -104,14 +101,17 @@ impl<'config, 'worker> ModuleCacheEntry<'config, 'worker> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
fn from_inner(inner: ModuleCacheEntryInner<'config, 'worker>) -> Self {
|
fn from_inner(inner: ModuleCacheEntryInner<'config>) -> Self {
|
||||||
Self(Some(inner))
|
Self(Some(inner))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_data(&self) -> Option<ModuleCacheData> {
|
pub fn get_data(&self) -> Option<ModuleCacheData> {
|
||||||
if let Some(inner) = &self.0 {
|
if let Some(inner) = &self.0 {
|
||||||
inner.get_data().map(|val| {
|
inner.get_data().map(|val| {
|
||||||
inner.worker.on_cache_get_async(&inner.mod_cache_path); // call on success
|
inner
|
||||||
|
.cache_config
|
||||||
|
.worker()
|
||||||
|
.on_cache_get_async(&inner.mod_cache_path); // call on success
|
||||||
val
|
val
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
@@ -122,13 +122,16 @@ impl<'config, 'worker> ModuleCacheEntry<'config, 'worker> {
|
|||||||
pub fn update_data(&self, data: &ModuleCacheData) {
|
pub fn update_data(&self, data: &ModuleCacheData) {
|
||||||
if let Some(inner) = &self.0 {
|
if let Some(inner) = &self.0 {
|
||||||
if inner.update_data(data).is_some() {
|
if inner.update_data(data).is_some() {
|
||||||
inner.worker.on_cache_update_async(&inner.mod_cache_path); // call on success
|
inner
|
||||||
|
.cache_config
|
||||||
|
.worker()
|
||||||
|
.on_cache_update_async(&inner.mod_cache_path); // call on success
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'config, 'worker> ModuleCacheEntryInner<'config, 'worker> {
|
impl<'config> ModuleCacheEntryInner<'config> {
|
||||||
fn new<'data>(
|
fn new<'data>(
|
||||||
module: &Module,
|
module: &Module,
|
||||||
function_body_inputs: &PrimaryMap<DefinedFuncIndex, FunctionBodyData<'data>>,
|
function_body_inputs: &PrimaryMap<DefinedFuncIndex, FunctionBodyData<'data>>,
|
||||||
@@ -136,7 +139,6 @@ impl<'config, 'worker> ModuleCacheEntryInner<'config, 'worker> {
|
|||||||
compiler_name: &str,
|
compiler_name: &str,
|
||||||
generate_debug_info: bool,
|
generate_debug_info: bool,
|
||||||
cache_config: &'config CacheConfig,
|
cache_config: &'config CacheConfig,
|
||||||
worker: &'worker Worker,
|
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let hash = Sha256Hasher::digest(module, function_body_inputs);
|
let hash = Sha256Hasher::digest(module, function_body_inputs);
|
||||||
let compiler_dir = if cfg!(debug_assertions) {
|
let compiler_dir = if cfg!(debug_assertions) {
|
||||||
@@ -167,7 +169,6 @@ impl<'config, 'worker> ModuleCacheEntryInner<'config, 'worker> {
|
|||||||
Self {
|
Self {
|
||||||
mod_cache_path,
|
mod_cache_path,
|
||||||
cache_config,
|
cache_config,
|
||||||
worker,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
260
crates/environ/src/cache/config.rs
vendored
260
crates/environ/src/cache/config.rs
vendored
@@ -1,20 +1,16 @@
|
|||||||
//! Module for configuring the cache system.
|
//! Module for configuring the cache system.
|
||||||
|
|
||||||
use super::worker;
|
use super::Worker;
|
||||||
use anyhow::{anyhow, bail, Context, Result};
|
use anyhow::{anyhow, bail, Context, Result};
|
||||||
use directories::ProjectDirs;
|
use directories::ProjectDirs;
|
||||||
use lazy_static::lazy_static;
|
use log::{trace, warn};
|
||||||
use log::{debug, error, trace, warn};
|
|
||||||
use serde::{
|
use serde::{
|
||||||
de::{self, Deserializer},
|
de::{self, Deserializer},
|
||||||
Deserialize,
|
Deserialize,
|
||||||
};
|
};
|
||||||
use spin::Once;
|
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::mem;
|
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::sync::atomic::{AtomicBool, Ordering};
|
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
// wrapped, so we have named section in config,
|
// wrapped, so we have named section in config,
|
||||||
@@ -25,12 +21,10 @@ struct Config {
|
|||||||
cache: CacheConfig,
|
cache: CacheConfig,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Global configuration for how the cache is managed
|
||||||
#[derive(Deserialize, Debug, Clone)]
|
#[derive(Deserialize, Debug, Clone)]
|
||||||
#[serde(deny_unknown_fields)]
|
#[serde(deny_unknown_fields)]
|
||||||
pub struct CacheConfig {
|
pub struct CacheConfig {
|
||||||
#[serde(skip)]
|
|
||||||
errors: Vec<String>,
|
|
||||||
|
|
||||||
enabled: bool,
|
enabled: bool,
|
||||||
directory: Option<PathBuf>,
|
directory: Option<PathBuf>,
|
||||||
#[serde(
|
#[serde(
|
||||||
@@ -91,49 +85,9 @@ pub struct CacheConfig {
|
|||||||
deserialize_with = "deserialize_percent"
|
deserialize_with = "deserialize_percent"
|
||||||
)]
|
)]
|
||||||
files_total_size_limit_percent_if_deleting: Option<u8>,
|
files_total_size_limit_percent_if_deleting: Option<u8>,
|
||||||
}
|
|
||||||
|
|
||||||
// Private static, so only internal function can access it.
|
#[serde(skip)]
|
||||||
static CONFIG: Once<CacheConfig> = Once::new();
|
worker: Option<Worker>,
|
||||||
static INIT_CALLED: AtomicBool = AtomicBool::new(false);
|
|
||||||
|
|
||||||
/// Returns cache configuration.
|
|
||||||
///
|
|
||||||
/// If system has not been initialized, it disables it.
|
|
||||||
/// You mustn't call init() after it.
|
|
||||||
pub fn cache_config() -> &'static CacheConfig {
|
|
||||||
CONFIG.call_once(CacheConfig::new_cache_disabled)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Initializes the cache system. Should be called exactly once,
|
|
||||||
/// and before using the cache system. Otherwise it can panic.
|
|
||||||
/// Returns list of errors. If empty, initialization succeeded.
|
|
||||||
pub fn init<P: AsRef<Path> + Debug>(
|
|
||||||
enabled: bool,
|
|
||||||
config_file: Option<P>,
|
|
||||||
init_file_per_thread_logger: Option<&'static str>,
|
|
||||||
) -> &'static Vec<String> {
|
|
||||||
INIT_CALLED
|
|
||||||
.compare_exchange(false, true, Ordering::SeqCst, Ordering::SeqCst)
|
|
||||||
.expect("Cache system init must be called at most once");
|
|
||||||
assert!(
|
|
||||||
CONFIG.r#try().is_none(),
|
|
||||||
"Cache system init must be called before using the system."
|
|
||||||
);
|
|
||||||
let conf_file_str = format!("{:?}", config_file);
|
|
||||||
let conf = CONFIG.call_once(|| CacheConfig::from_file(enabled, config_file));
|
|
||||||
if conf.errors.is_empty() {
|
|
||||||
if conf.enabled() {
|
|
||||||
worker::init(init_file_per_thread_logger);
|
|
||||||
}
|
|
||||||
debug!("Cache init(\"{}\"): {:#?}", conf_file_str, conf)
|
|
||||||
} else {
|
|
||||||
error!(
|
|
||||||
"Cache init(\"{}\"): errors: {:#?}",
|
|
||||||
conf_file_str, conf.errors,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
&conf.errors
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a new configuration file at specified path, or default path if None is passed.
|
/// Creates a new configuration file at specified path, or default path if None is passed.
|
||||||
@@ -141,13 +95,10 @@ pub fn init<P: AsRef<Path> + Debug>(
|
|||||||
pub fn create_new_config<P: AsRef<Path> + Debug>(config_file: Option<P>) -> Result<PathBuf> {
|
pub fn create_new_config<P: AsRef<Path> + Debug>(config_file: Option<P>) -> Result<PathBuf> {
|
||||||
trace!("Creating new config file, path: {:?}", config_file);
|
trace!("Creating new config file, path: {:?}", config_file);
|
||||||
|
|
||||||
let config_file = config_file
|
let config_file = match config_file {
|
||||||
.as_ref()
|
Some(path) => path.as_ref().to_path_buf(),
|
||||||
.map_or_else(
|
None => default_config_path()?,
|
||||||
|| DEFAULT_CONFIG_PATH.as_ref().map(|p| p.as_ref()),
|
};
|
||||||
|p| Ok(p.as_ref()),
|
|
||||||
)
|
|
||||||
.map_err(|s| anyhow!("{}", s))?;
|
|
||||||
|
|
||||||
if config_file.exists() {
|
if config_file.exists() {
|
||||||
bail!(
|
bail!(
|
||||||
@@ -188,14 +139,6 @@ enabled = true
|
|||||||
|
|
||||||
// permitted levels from: https://docs.rs/zstd/0.4.28+zstd.1.4.3/zstd/stream/write/struct.Encoder.html
|
// permitted levels from: https://docs.rs/zstd/0.4.28+zstd.1.4.3/zstd/stream/write/struct.Encoder.html
|
||||||
const ZSTD_COMPRESSION_LEVELS: std::ops::RangeInclusive<i32> = 0..=21;
|
const ZSTD_COMPRESSION_LEVELS: std::ops::RangeInclusive<i32> = 0..=21;
|
||||||
lazy_static! {
|
|
||||||
static ref PROJECT_DIRS: Option<ProjectDirs> =
|
|
||||||
ProjectDirs::from("", "BytecodeAlliance", "wasmtime");
|
|
||||||
static ref DEFAULT_CONFIG_PATH: Result<PathBuf, String> = PROJECT_DIRS
|
|
||||||
.as_ref()
|
|
||||||
.map(|proj_dirs| proj_dirs.config_dir().join("config.toml"))
|
|
||||||
.ok_or_else(|| "Config file not specified and failed to get the default".to_string());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Default settings, you're welcome to tune them!
|
// Default settings, you're welcome to tune them!
|
||||||
// TODO: what do we want to warn users about?
|
// TODO: what do we want to warn users about?
|
||||||
@@ -232,6 +175,17 @@ const DEFAULT_FILE_COUNT_LIMIT_PERCENT_IF_DELETING: u8 = 70;
|
|||||||
// if changed, update cli-cache.md
|
// if changed, update cli-cache.md
|
||||||
const DEFAULT_FILES_TOTAL_SIZE_LIMIT_PERCENT_IF_DELETING: u8 = 70;
|
const DEFAULT_FILES_TOTAL_SIZE_LIMIT_PERCENT_IF_DELETING: u8 = 70;
|
||||||
|
|
||||||
|
fn project_dirs() -> Option<ProjectDirs> {
|
||||||
|
ProjectDirs::from("", "BytecodeAlliance", "wasmtime")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn default_config_path() -> Result<PathBuf> {
|
||||||
|
match project_dirs() {
|
||||||
|
Some(dirs) => Ok(dirs.config_dir().join("config.toml")),
|
||||||
|
None => bail!("config file not specified and failed to get the default"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Deserializers of our custom formats
|
// Deserializers of our custom formats
|
||||||
// can be replaced with const generics later
|
// can be replaced with const generics later
|
||||||
macro_rules! generate_deserializer {
|
macro_rules! generate_deserializer {
|
||||||
@@ -353,9 +307,9 @@ impl CacheConfig {
|
|||||||
.expect(CACHE_IMPROPER_CONFIG_ERROR_MSG)
|
.expect(CACHE_IMPROPER_CONFIG_ERROR_MSG)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Creates a new set of configuration which represents a disabled cache
|
||||||
pub fn new_cache_disabled() -> Self {
|
pub fn new_cache_disabled() -> Self {
|
||||||
Self {
|
Self {
|
||||||
errors: Vec::new(),
|
|
||||||
enabled: false,
|
enabled: false,
|
||||||
directory: None,
|
directory: None,
|
||||||
worker_event_queue_size: None,
|
worker_event_queue_size: None,
|
||||||
@@ -369,6 +323,7 @@ impl CacheConfig {
|
|||||||
files_total_size_soft_limit: None,
|
files_total_size_soft_limit: None,
|
||||||
file_count_limit_percent_if_deleting: None,
|
file_count_limit_percent_if_deleting: None,
|
||||||
files_total_size_limit_percent_if_deleting: None,
|
files_total_size_limit_percent_if_deleting: None,
|
||||||
|
worker: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -378,78 +333,70 @@ impl CacheConfig {
|
|||||||
conf
|
conf
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new_cache_with_errors(errors: Vec<String>) -> Self {
|
/// Parses cache configuration from the file specified
|
||||||
let mut conf = Self::new_cache_disabled();
|
pub fn from_file(config_file: Option<&Path>) -> Result<Self> {
|
||||||
conf.errors = errors;
|
let mut config = Self::load_and_parse_file(config_file)?;
|
||||||
conf
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn from_file<P: AsRef<Path>>(enabled: bool, config_file: Option<P>) -> Self {
|
|
||||||
if !enabled {
|
|
||||||
return Self::new_cache_disabled();
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut config = match Self::load_and_parse_file(config_file) {
|
|
||||||
Ok(data) => data,
|
|
||||||
Err(err) => return Self::new_cache_with_errors(vec![err]),
|
|
||||||
};
|
|
||||||
|
|
||||||
// validate values and fill in defaults
|
// validate values and fill in defaults
|
||||||
config.validate_directory_or_default();
|
config.validate_directory_or_default()?;
|
||||||
config.validate_worker_event_queue_size_or_default();
|
config.validate_worker_event_queue_size_or_default();
|
||||||
config.validate_baseline_compression_level_or_default();
|
config.validate_baseline_compression_level_or_default()?;
|
||||||
config.validate_optimized_compression_level_or_default();
|
config.validate_optimized_compression_level_or_default()?;
|
||||||
config.validate_optimized_compression_usage_counter_threshold_or_default();
|
config.validate_optimized_compression_usage_counter_threshold_or_default();
|
||||||
config.validate_cleanup_interval_or_default();
|
config.validate_cleanup_interval_or_default();
|
||||||
config.validate_optimizing_compression_task_timeout_or_default();
|
config.validate_optimizing_compression_task_timeout_or_default();
|
||||||
config.validate_allowed_clock_drift_for_files_from_future_or_default();
|
config.validate_allowed_clock_drift_for_files_from_future_or_default();
|
||||||
config.validate_file_count_soft_limit_or_default();
|
config.validate_file_count_soft_limit_or_default();
|
||||||
config.validate_files_total_size_soft_limit_or_default();
|
config.validate_files_total_size_soft_limit_or_default();
|
||||||
config.validate_file_count_limit_percent_if_deleting_or_default();
|
config.validate_file_count_limit_percent_if_deleting_or_default()?;
|
||||||
config.validate_files_total_size_limit_percent_if_deleting_or_default();
|
config.validate_files_total_size_limit_percent_if_deleting_or_default()?;
|
||||||
|
config.spawn_worker();
|
||||||
|
|
||||||
config.disable_if_any_error();
|
Ok(config)
|
||||||
config
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_and_parse_file<P: AsRef<Path>>(config_file: Option<P>) -> Result<Self, String> {
|
fn spawn_worker(&mut self) {
|
||||||
|
if self.enabled {
|
||||||
|
self.worker = Some(Worker::start_new(self, None));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn worker(&self) -> &Worker {
|
||||||
|
assert!(self.enabled);
|
||||||
|
self.worker.as_ref().unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn load_and_parse_file(config_file: Option<&Path>) -> Result<Self> {
|
||||||
// get config file path
|
// get config file path
|
||||||
let (config_file, user_custom_file) = config_file.as_ref().map_or_else(
|
let (config_file, user_custom_file) = match config_file {
|
||||||
|| DEFAULT_CONFIG_PATH.as_ref().map(|p| (p.as_ref(), false)),
|
Some(path) => (path.to_path_buf(), true),
|
||||||
|p| Ok((p.as_ref(), true)),
|
None => (default_config_path()?, false),
|
||||||
)?;
|
};
|
||||||
|
|
||||||
// read config, or use default one
|
// read config, or use default one
|
||||||
let entity_exists = config_file.exists();
|
let entity_exists = config_file.exists();
|
||||||
match (entity_exists, user_custom_file) {
|
match (entity_exists, user_custom_file) {
|
||||||
(false, false) => Ok(Self::new_cache_enabled_template()),
|
(false, false) => Ok(Self::new_cache_enabled_template()),
|
||||||
_ => match fs::read(&config_file) {
|
_ => {
|
||||||
Ok(bytes) => match toml::from_slice::<Config>(&bytes[..]) {
|
let bytes = fs::read(&config_file).context(format!(
|
||||||
Ok(config) => Ok(config.cache),
|
"failed to read config file: {}",
|
||||||
Err(err) => Err(format!(
|
config_file.display()
|
||||||
"Failed to parse config file, path: {}, error: {}",
|
))?;
|
||||||
config_file.display(),
|
let config = toml::from_slice::<Config>(&bytes[..]).context(format!(
|
||||||
err
|
"failed to parse config file: {}",
|
||||||
)),
|
config_file.display()
|
||||||
},
|
))?;
|
||||||
Err(err) => Err(format!(
|
Ok(config.cache)
|
||||||
"Failed to read config file, path: {}, error: {}",
|
}
|
||||||
config_file.display(),
|
|
||||||
err
|
|
||||||
)),
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn validate_directory_or_default(&mut self) {
|
fn validate_directory_or_default(&mut self) -> Result<()> {
|
||||||
if self.directory.is_none() {
|
if self.directory.is_none() {
|
||||||
match &*PROJECT_DIRS {
|
match project_dirs() {
|
||||||
Some(proj_dirs) => self.directory = Some(proj_dirs.cache_dir().to_path_buf()),
|
Some(proj_dirs) => self.directory = Some(proj_dirs.cache_dir().to_path_buf()),
|
||||||
None => {
|
None => {
|
||||||
self.errors.push(
|
bail!("Cache directory not specified and failed to get the default");
|
||||||
"Cache directory not specified and failed to get the default".to_string(),
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -461,35 +408,22 @@ impl CacheConfig {
|
|||||||
let cache_dir = self.directory.as_ref().unwrap();
|
let cache_dir = self.directory.as_ref().unwrap();
|
||||||
|
|
||||||
if !cache_dir.is_absolute() {
|
if !cache_dir.is_absolute() {
|
||||||
self.errors.push(format!(
|
bail!(
|
||||||
"Cache directory path has to be absolute, path: {}",
|
"Cache directory path has to be absolute, path: {}",
|
||||||
cache_dir.display(),
|
cache_dir.display(),
|
||||||
));
|
);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
match fs::create_dir_all(cache_dir) {
|
fs::create_dir_all(cache_dir).context(format!(
|
||||||
Ok(()) => (),
|
"failed to create cache directory: {}",
|
||||||
Err(err) => {
|
cache_dir.display()
|
||||||
self.errors.push(format!(
|
))?;
|
||||||
"Failed to create the cache directory, path: {}, error: {}",
|
let canonical = fs::canonicalize(cache_dir).context(format!(
|
||||||
cache_dir.display(),
|
"failed to canonicalize cache directory: {}",
|
||||||
err
|
cache_dir.display()
|
||||||
));
|
))?;
|
||||||
return;
|
self.directory = Some(canonical);
|
||||||
}
|
Ok(())
|
||||||
};
|
|
||||||
|
|
||||||
match fs::canonicalize(cache_dir) {
|
|
||||||
Ok(p) => self.directory = Some(p),
|
|
||||||
Err(err) => {
|
|
||||||
self.errors.push(format!(
|
|
||||||
"Failed to canonicalize the cache directory, path: {}, error: {}",
|
|
||||||
cache_dir.display(),
|
|
||||||
err
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn validate_worker_event_queue_size_or_default(&mut self) {
|
fn validate_worker_event_queue_size_or_default(&mut self) {
|
||||||
@@ -502,22 +436,23 @@ impl CacheConfig {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn validate_baseline_compression_level_or_default(&mut self) {
|
fn validate_baseline_compression_level_or_default(&mut self) -> Result<()> {
|
||||||
if self.baseline_compression_level.is_none() {
|
if self.baseline_compression_level.is_none() {
|
||||||
self.baseline_compression_level = Some(DEFAULT_BASELINE_COMPRESSION_LEVEL);
|
self.baseline_compression_level = Some(DEFAULT_BASELINE_COMPRESSION_LEVEL);
|
||||||
}
|
}
|
||||||
|
|
||||||
if !ZSTD_COMPRESSION_LEVELS.contains(&self.baseline_compression_level.unwrap()) {
|
if !ZSTD_COMPRESSION_LEVELS.contains(&self.baseline_compression_level.unwrap()) {
|
||||||
self.errors.push(format!(
|
bail!(
|
||||||
"Invalid baseline compression level: {} not in {:#?}",
|
"Invalid baseline compression level: {} not in {:#?}",
|
||||||
self.baseline_compression_level.unwrap(),
|
self.baseline_compression_level.unwrap(),
|
||||||
ZSTD_COMPRESSION_LEVELS
|
ZSTD_COMPRESSION_LEVELS
|
||||||
));
|
);
|
||||||
}
|
}
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
// assumption: baseline compression level has been verified
|
// assumption: baseline compression level has been verified
|
||||||
fn validate_optimized_compression_level_or_default(&mut self) {
|
fn validate_optimized_compression_level_or_default(&mut self) -> Result<()> {
|
||||||
if self.optimized_compression_level.is_none() {
|
if self.optimized_compression_level.is_none() {
|
||||||
self.optimized_compression_level = Some(DEFAULT_OPTIMIZED_COMPRESSION_LEVEL);
|
self.optimized_compression_level = Some(DEFAULT_OPTIMIZED_COMPRESSION_LEVEL);
|
||||||
}
|
}
|
||||||
@@ -526,18 +461,21 @@ impl CacheConfig {
|
|||||||
let base_lvl = self.baseline_compression_level.unwrap();
|
let base_lvl = self.baseline_compression_level.unwrap();
|
||||||
|
|
||||||
if !ZSTD_COMPRESSION_LEVELS.contains(&opt_lvl) {
|
if !ZSTD_COMPRESSION_LEVELS.contains(&opt_lvl) {
|
||||||
self.errors.push(format!(
|
bail!(
|
||||||
"Invalid optimized compression level: {} not in {:#?}",
|
"Invalid optimized compression level: {} not in {:#?}",
|
||||||
opt_lvl, ZSTD_COMPRESSION_LEVELS
|
opt_lvl,
|
||||||
));
|
ZSTD_COMPRESSION_LEVELS
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if opt_lvl < base_lvl {
|
if opt_lvl < base_lvl {
|
||||||
self.errors.push(format!(
|
bail!(
|
||||||
"Invalid optimized compression level is lower than baseline: {} < {}",
|
"Invalid optimized compression level is lower than baseline: {} < {}",
|
||||||
opt_lvl, base_lvl
|
opt_lvl,
|
||||||
));
|
base_lvl
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn validate_optimized_compression_usage_counter_threshold_or_default(&mut self) {
|
fn validate_optimized_compression_usage_counter_threshold_or_default(&mut self) {
|
||||||
@@ -579,7 +517,7 @@ impl CacheConfig {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn validate_file_count_limit_percent_if_deleting_or_default(&mut self) {
|
fn validate_file_count_limit_percent_if_deleting_or_default(&mut self) -> Result<()> {
|
||||||
if self.file_count_limit_percent_if_deleting.is_none() {
|
if self.file_count_limit_percent_if_deleting.is_none() {
|
||||||
self.file_count_limit_percent_if_deleting =
|
self.file_count_limit_percent_if_deleting =
|
||||||
Some(DEFAULT_FILE_COUNT_LIMIT_PERCENT_IF_DELETING);
|
Some(DEFAULT_FILE_COUNT_LIMIT_PERCENT_IF_DELETING);
|
||||||
@@ -587,14 +525,15 @@ impl CacheConfig {
|
|||||||
|
|
||||||
let percent = self.file_count_limit_percent_if_deleting.unwrap();
|
let percent = self.file_count_limit_percent_if_deleting.unwrap();
|
||||||
if percent > 100 {
|
if percent > 100 {
|
||||||
self.errors.push(format!(
|
bail!(
|
||||||
"Invalid files count limit percent if deleting: {} not in range 0-100%",
|
"Invalid files count limit percent if deleting: {} not in range 0-100%",
|
||||||
percent
|
percent
|
||||||
));
|
);
|
||||||
}
|
}
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn validate_files_total_size_limit_percent_if_deleting_or_default(&mut self) {
|
fn validate_files_total_size_limit_percent_if_deleting_or_default(&mut self) -> Result<()> {
|
||||||
if self.files_total_size_limit_percent_if_deleting.is_none() {
|
if self.files_total_size_limit_percent_if_deleting.is_none() {
|
||||||
self.files_total_size_limit_percent_if_deleting =
|
self.files_total_size_limit_percent_if_deleting =
|
||||||
Some(DEFAULT_FILES_TOTAL_SIZE_LIMIT_PERCENT_IF_DELETING);
|
Some(DEFAULT_FILES_TOTAL_SIZE_LIMIT_PERCENT_IF_DELETING);
|
||||||
@@ -602,19 +541,12 @@ impl CacheConfig {
|
|||||||
|
|
||||||
let percent = self.files_total_size_limit_percent_if_deleting.unwrap();
|
let percent = self.files_total_size_limit_percent_if_deleting.unwrap();
|
||||||
if percent > 100 {
|
if percent > 100 {
|
||||||
self.errors.push(format!(
|
bail!(
|
||||||
"Invalid files total size limit percent if deleting: {} not in range 0-100%",
|
"Invalid files total size limit percent if deleting: {} not in range 0-100%",
|
||||||
percent
|
percent
|
||||||
));
|
);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn disable_if_any_error(&mut self) {
|
|
||||||
if !self.errors.is_empty() {
|
|
||||||
let mut conf = Self::new_cache_disabled();
|
|
||||||
mem::swap(self, &mut conf);
|
|
||||||
mem::swap(&mut self.errors, &mut conf.errors);
|
|
||||||
}
|
}
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
134
crates/environ/src/cache/config/tests.rs
vendored
134
crates/environ/src/cache/config/tests.rs
vendored
@@ -24,7 +24,19 @@ macro_rules! load_config {
|
|||||||
cache_dir = toml::to_string_pretty(&format!("{}", $cache_dir.display())).unwrap()
|
cache_dir = toml::to_string_pretty(&format!("{}", $cache_dir.display())).unwrap()
|
||||||
);
|
);
|
||||||
fs::write(config_path, content).expect("Failed to write test config file");
|
fs::write(config_path, content).expect("Failed to write test config file");
|
||||||
CacheConfig::from_file(true, Some(config_path))
|
CacheConfig::from_file(Some(config_path)).unwrap()
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! bad_config {
|
||||||
|
($config_path:ident, $content_fmt:expr, $cache_dir:ident) => {{
|
||||||
|
let config_path = &$config_path;
|
||||||
|
let content = format!(
|
||||||
|
$content_fmt,
|
||||||
|
cache_dir = toml::to_string_pretty(&format!("{}", $cache_dir.display())).unwrap()
|
||||||
|
);
|
||||||
|
fs::write(config_path, content).expect("Failed to write test config file");
|
||||||
|
assert!(CacheConfig::from_file(Some(config_path)).is_err());
|
||||||
}};
|
}};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -33,25 +45,17 @@ macro_rules! load_config {
|
|||||||
fn test_disabled() {
|
fn test_disabled() {
|
||||||
let dir = tempfile::tempdir().expect("Can't create temporary directory");
|
let dir = tempfile::tempdir().expect("Can't create temporary directory");
|
||||||
let config_path = dir.path().join("cache-config.toml");
|
let config_path = dir.path().join("cache-config.toml");
|
||||||
let config_content = "[cache]\n\
|
|
||||||
enabled = true\n";
|
|
||||||
fs::write(&config_path, config_content).expect("Failed to write test config file");
|
|
||||||
let conf = CacheConfig::from_file(false, Some(&config_path));
|
|
||||||
assert!(!conf.enabled());
|
|
||||||
assert!(conf.errors.is_empty());
|
|
||||||
|
|
||||||
let config_content = "[cache]\n\
|
let config_content = "[cache]\n\
|
||||||
enabled = false\n";
|
enabled = false\n";
|
||||||
fs::write(&config_path, config_content).expect("Failed to write test config file");
|
fs::write(&config_path, config_content).expect("Failed to write test config file");
|
||||||
let conf = CacheConfig::from_file(true, Some(&config_path));
|
let conf = CacheConfig::from_file(Some(&config_path)).unwrap();
|
||||||
assert!(!conf.enabled());
|
assert!(!conf.enabled());
|
||||||
assert!(conf.errors.is_empty());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_unrecognized_settings() {
|
fn test_unrecognized_settings() {
|
||||||
let (_td, cd, cp) = test_prolog();
|
let (_td, cd, cp) = test_prolog();
|
||||||
let conf = load_config!(
|
bad_config!(
|
||||||
cp,
|
cp,
|
||||||
"unrecognized-setting = 42\n\
|
"unrecognized-setting = 42\n\
|
||||||
[cache]\n\
|
[cache]\n\
|
||||||
@@ -59,10 +63,8 @@ fn test_unrecognized_settings() {
|
|||||||
directory = {cache_dir}",
|
directory = {cache_dir}",
|
||||||
cd
|
cd
|
||||||
);
|
);
|
||||||
assert!(!conf.enabled());
|
|
||||||
assert!(!conf.errors.is_empty());
|
|
||||||
|
|
||||||
let conf = load_config!(
|
bad_config!(
|
||||||
cp,
|
cp,
|
||||||
"[cache]\n\
|
"[cache]\n\
|
||||||
enabled = true\n\
|
enabled = true\n\
|
||||||
@@ -70,8 +72,6 @@ fn test_unrecognized_settings() {
|
|||||||
unrecognized-setting = 42",
|
unrecognized-setting = 42",
|
||||||
cd
|
cd
|
||||||
);
|
);
|
||||||
assert!(!conf.enabled());
|
|
||||||
assert!(!conf.errors.is_empty());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -119,9 +119,7 @@ fn test_all_settings() {
|
|||||||
check_conf(&conf, &cd);
|
check_conf(&conf, &cd);
|
||||||
|
|
||||||
fn check_conf(conf: &CacheConfig, cd: &PathBuf) {
|
fn check_conf(conf: &CacheConfig, cd: &PathBuf) {
|
||||||
eprintln!("errors: {:#?}", conf.errors);
|
|
||||||
assert!(conf.enabled());
|
assert!(conf.enabled());
|
||||||
assert!(conf.errors.is_empty());
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
conf.directory(),
|
conf.directory(),
|
||||||
&fs::canonicalize(cd).expect("canonicalize failed")
|
&fs::canonicalize(cd).expect("canonicalize failed")
|
||||||
@@ -159,11 +157,10 @@ fn test_compression_level_settings() {
|
|||||||
cd
|
cd
|
||||||
);
|
);
|
||||||
assert!(conf.enabled());
|
assert!(conf.enabled());
|
||||||
assert!(conf.errors.is_empty());
|
|
||||||
assert_eq!(conf.baseline_compression_level(), 1);
|
assert_eq!(conf.baseline_compression_level(), 1);
|
||||||
assert_eq!(conf.optimized_compression_level(), 21);
|
assert_eq!(conf.optimized_compression_level(), 21);
|
||||||
|
|
||||||
let conf = load_config!(
|
bad_config!(
|
||||||
cp,
|
cp,
|
||||||
"[cache]\n\
|
"[cache]\n\
|
||||||
enabled = true\n\
|
enabled = true\n\
|
||||||
@@ -172,10 +169,8 @@ fn test_compression_level_settings() {
|
|||||||
optimized-compression-level = 21",
|
optimized-compression-level = 21",
|
||||||
cd
|
cd
|
||||||
);
|
);
|
||||||
assert!(!conf.enabled());
|
|
||||||
assert!(!conf.errors.is_empty());
|
|
||||||
|
|
||||||
let conf = load_config!(
|
bad_config!(
|
||||||
cp,
|
cp,
|
||||||
"[cache]\n\
|
"[cache]\n\
|
||||||
enabled = true\n\
|
enabled = true\n\
|
||||||
@@ -184,8 +179,6 @@ fn test_compression_level_settings() {
|
|||||||
optimized-compression-level = 10",
|
optimized-compression-level = 10",
|
||||||
cd
|
cd
|
||||||
);
|
);
|
||||||
assert!(!conf.enabled());
|
|
||||||
assert!(!conf.errors.is_empty());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -202,7 +195,6 @@ fn test_si_prefix_settings() {
|
|||||||
cd
|
cd
|
||||||
);
|
);
|
||||||
assert!(conf.enabled());
|
assert!(conf.enabled());
|
||||||
assert!(conf.errors.is_empty());
|
|
||||||
assert_eq!(conf.worker_event_queue_size(), 42);
|
assert_eq!(conf.worker_event_queue_size(), 42);
|
||||||
assert_eq!(conf.optimized_compression_usage_counter_threshold(), 4_000);
|
assert_eq!(conf.optimized_compression_usage_counter_threshold(), 4_000);
|
||||||
assert_eq!(conf.file_count_soft_limit(), 3_000_000);
|
assert_eq!(conf.file_count_soft_limit(), 3_000_000);
|
||||||
@@ -212,14 +204,13 @@ fn test_si_prefix_settings() {
|
|||||||
"[cache]\n\
|
"[cache]\n\
|
||||||
enabled = true\n\
|
enabled = true\n\
|
||||||
directory = {cache_dir}\n\
|
directory = {cache_dir}\n\
|
||||||
worker-event-queue-size = '2G'\n\
|
worker-event-queue-size = '2K'\n\
|
||||||
optimized-compression-usage-counter-threshold = '4444T'\n\
|
optimized-compression-usage-counter-threshold = '4444T'\n\
|
||||||
file-count-soft-limit = '1P'",
|
file-count-soft-limit = '1P'",
|
||||||
cd
|
cd
|
||||||
);
|
);
|
||||||
assert!(conf.enabled());
|
assert!(conf.enabled());
|
||||||
assert!(conf.errors.is_empty());
|
assert_eq!(conf.worker_event_queue_size(), 2_000);
|
||||||
assert_eq!(conf.worker_event_queue_size(), 2_000_000_000);
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
conf.optimized_compression_usage_counter_threshold(),
|
conf.optimized_compression_usage_counter_threshold(),
|
||||||
4_444_000_000_000_000
|
4_444_000_000_000_000
|
||||||
@@ -227,7 +218,7 @@ fn test_si_prefix_settings() {
|
|||||||
assert_eq!(conf.file_count_soft_limit(), 1_000_000_000_000_000);
|
assert_eq!(conf.file_count_soft_limit(), 1_000_000_000_000_000);
|
||||||
|
|
||||||
// different errors
|
// different errors
|
||||||
let conf = load_config!(
|
bad_config!(
|
||||||
cp,
|
cp,
|
||||||
"[cache]\n\
|
"[cache]\n\
|
||||||
enabled = true\n\
|
enabled = true\n\
|
||||||
@@ -235,10 +226,8 @@ fn test_si_prefix_settings() {
|
|||||||
worker-event-queue-size = '2g'",
|
worker-event-queue-size = '2g'",
|
||||||
cd
|
cd
|
||||||
);
|
);
|
||||||
assert!(!conf.enabled());
|
|
||||||
assert!(!conf.errors.is_empty());
|
|
||||||
|
|
||||||
let conf = load_config!(
|
bad_config!(
|
||||||
cp,
|
cp,
|
||||||
"[cache]\n\
|
"[cache]\n\
|
||||||
enabled = true\n\
|
enabled = true\n\
|
||||||
@@ -246,10 +235,8 @@ fn test_si_prefix_settings() {
|
|||||||
file-count-soft-limit = 1",
|
file-count-soft-limit = 1",
|
||||||
cd
|
cd
|
||||||
);
|
);
|
||||||
assert!(!conf.enabled());
|
|
||||||
assert!(!conf.errors.is_empty());
|
|
||||||
|
|
||||||
let conf = load_config!(
|
bad_config!(
|
||||||
cp,
|
cp,
|
||||||
"[cache]\n\
|
"[cache]\n\
|
||||||
enabled = true\n\
|
enabled = true\n\
|
||||||
@@ -257,10 +244,8 @@ fn test_si_prefix_settings() {
|
|||||||
file-count-soft-limit = '-31337'",
|
file-count-soft-limit = '-31337'",
|
||||||
cd
|
cd
|
||||||
);
|
);
|
||||||
assert!(!conf.enabled());
|
|
||||||
assert!(!conf.errors.is_empty());
|
|
||||||
|
|
||||||
let conf = load_config!(
|
bad_config!(
|
||||||
cp,
|
cp,
|
||||||
"[cache]\n\
|
"[cache]\n\
|
||||||
enabled = true\n\
|
enabled = true\n\
|
||||||
@@ -268,8 +253,6 @@ fn test_si_prefix_settings() {
|
|||||||
file-count-soft-limit = '3.14M'",
|
file-count-soft-limit = '3.14M'",
|
||||||
cd
|
cd
|
||||||
);
|
);
|
||||||
assert!(!conf.enabled());
|
|
||||||
assert!(!conf.errors.is_empty());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -284,7 +267,6 @@ fn test_disk_space_settings() {
|
|||||||
cd
|
cd
|
||||||
);
|
);
|
||||||
assert!(conf.enabled());
|
assert!(conf.enabled());
|
||||||
assert!(conf.errors.is_empty());
|
|
||||||
assert_eq!(conf.files_total_size_soft_limit(), 76);
|
assert_eq!(conf.files_total_size_soft_limit(), 76);
|
||||||
|
|
||||||
let conf = load_config!(
|
let conf = load_config!(
|
||||||
@@ -296,7 +278,6 @@ fn test_disk_space_settings() {
|
|||||||
cd
|
cd
|
||||||
);
|
);
|
||||||
assert!(conf.enabled());
|
assert!(conf.enabled());
|
||||||
assert!(conf.errors.is_empty());
|
|
||||||
assert_eq!(conf.files_total_size_soft_limit(), 42 * (1u64 << 20));
|
assert_eq!(conf.files_total_size_soft_limit(), 42 * (1u64 << 20));
|
||||||
|
|
||||||
let conf = load_config!(
|
let conf = load_config!(
|
||||||
@@ -308,7 +289,6 @@ fn test_disk_space_settings() {
|
|||||||
cd
|
cd
|
||||||
);
|
);
|
||||||
assert!(conf.enabled());
|
assert!(conf.enabled());
|
||||||
assert!(conf.errors.is_empty());
|
|
||||||
assert_eq!(conf.files_total_size_soft_limit(), 2 * (1u64 << 30));
|
assert_eq!(conf.files_total_size_soft_limit(), 2 * (1u64 << 30));
|
||||||
|
|
||||||
let conf = load_config!(
|
let conf = load_config!(
|
||||||
@@ -320,7 +300,6 @@ fn test_disk_space_settings() {
|
|||||||
cd
|
cd
|
||||||
);
|
);
|
||||||
assert!(conf.enabled());
|
assert!(conf.enabled());
|
||||||
assert!(conf.errors.is_empty());
|
|
||||||
assert_eq!(conf.files_total_size_soft_limit(), 31337 * (1u64 << 40));
|
assert_eq!(conf.files_total_size_soft_limit(), 31337 * (1u64 << 40));
|
||||||
|
|
||||||
let conf = load_config!(
|
let conf = load_config!(
|
||||||
@@ -332,7 +311,6 @@ fn test_disk_space_settings() {
|
|||||||
cd
|
cd
|
||||||
);
|
);
|
||||||
assert!(conf.enabled());
|
assert!(conf.enabled());
|
||||||
assert!(conf.errors.is_empty());
|
|
||||||
assert_eq!(conf.files_total_size_soft_limit(), 7 * (1u64 << 50));
|
assert_eq!(conf.files_total_size_soft_limit(), 7 * (1u64 << 50));
|
||||||
|
|
||||||
let conf = load_config!(
|
let conf = load_config!(
|
||||||
@@ -344,11 +322,10 @@ fn test_disk_space_settings() {
|
|||||||
cd
|
cd
|
||||||
);
|
);
|
||||||
assert!(conf.enabled());
|
assert!(conf.enabled());
|
||||||
assert!(conf.errors.is_empty());
|
|
||||||
assert_eq!(conf.files_total_size_soft_limit(), 7_000_000);
|
assert_eq!(conf.files_total_size_soft_limit(), 7_000_000);
|
||||||
|
|
||||||
// different errors
|
// different errors
|
||||||
let conf = load_config!(
|
bad_config!(
|
||||||
cp,
|
cp,
|
||||||
"[cache]\n\
|
"[cache]\n\
|
||||||
enabled = true\n\
|
enabled = true\n\
|
||||||
@@ -356,10 +333,8 @@ fn test_disk_space_settings() {
|
|||||||
files-total-size-soft-limit = '7 mi'",
|
files-total-size-soft-limit = '7 mi'",
|
||||||
cd
|
cd
|
||||||
);
|
);
|
||||||
assert!(!conf.enabled());
|
|
||||||
assert!(!conf.errors.is_empty());
|
|
||||||
|
|
||||||
let conf = load_config!(
|
bad_config!(
|
||||||
cp,
|
cp,
|
||||||
"[cache]\n\
|
"[cache]\n\
|
||||||
enabled = true\n\
|
enabled = true\n\
|
||||||
@@ -367,10 +342,8 @@ fn test_disk_space_settings() {
|
|||||||
files-total-size-soft-limit = 1",
|
files-total-size-soft-limit = 1",
|
||||||
cd
|
cd
|
||||||
);
|
);
|
||||||
assert!(!conf.enabled());
|
|
||||||
assert!(!conf.errors.is_empty());
|
|
||||||
|
|
||||||
let conf = load_config!(
|
bad_config!(
|
||||||
cp,
|
cp,
|
||||||
"[cache]\n\
|
"[cache]\n\
|
||||||
enabled = true\n\
|
enabled = true\n\
|
||||||
@@ -378,10 +351,8 @@ fn test_disk_space_settings() {
|
|||||||
files-total-size-soft-limit = '-31337'",
|
files-total-size-soft-limit = '-31337'",
|
||||||
cd
|
cd
|
||||||
);
|
);
|
||||||
assert!(!conf.enabled());
|
|
||||||
assert!(!conf.errors.is_empty());
|
|
||||||
|
|
||||||
let conf = load_config!(
|
bad_config!(
|
||||||
cp,
|
cp,
|
||||||
"[cache]\n\
|
"[cache]\n\
|
||||||
enabled = true\n\
|
enabled = true\n\
|
||||||
@@ -389,8 +360,6 @@ fn test_disk_space_settings() {
|
|||||||
files-total-size-soft-limit = '3.14Ki'",
|
files-total-size-soft-limit = '3.14Ki'",
|
||||||
cd
|
cd
|
||||||
);
|
);
|
||||||
assert!(!conf.enabled());
|
|
||||||
assert!(!conf.errors.is_empty());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -407,7 +376,6 @@ fn test_duration_settings() {
|
|||||||
cd
|
cd
|
||||||
);
|
);
|
||||||
assert!(conf.enabled());
|
assert!(conf.enabled());
|
||||||
assert!(conf.errors.is_empty());
|
|
||||||
assert_eq!(conf.cleanup_interval(), Duration::from_secs(100));
|
assert_eq!(conf.cleanup_interval(), Duration::from_secs(100));
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
conf.optimizing_compression_task_timeout(),
|
conf.optimizing_compression_task_timeout(),
|
||||||
@@ -428,7 +396,6 @@ fn test_duration_settings() {
|
|||||||
cd
|
cd
|
||||||
);
|
);
|
||||||
assert!(conf.enabled());
|
assert!(conf.enabled());
|
||||||
assert!(conf.errors.is_empty());
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
conf.cleanup_interval(),
|
conf.cleanup_interval(),
|
||||||
Duration::from_secs(2 * 24 * 60 * 60)
|
Duration::from_secs(2 * 24 * 60 * 60)
|
||||||
@@ -439,7 +406,7 @@ fn test_duration_settings() {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// different errors
|
// different errors
|
||||||
let conf = load_config!(
|
bad_config!(
|
||||||
cp,
|
cp,
|
||||||
"[cache]\n\
|
"[cache]\n\
|
||||||
enabled = true\n\
|
enabled = true\n\
|
||||||
@@ -447,10 +414,8 @@ fn test_duration_settings() {
|
|||||||
optimizing-compression-task-timeout = '333'",
|
optimizing-compression-task-timeout = '333'",
|
||||||
cd
|
cd
|
||||||
);
|
);
|
||||||
assert!(!conf.enabled());
|
|
||||||
assert!(!conf.errors.is_empty());
|
|
||||||
|
|
||||||
let conf = load_config!(
|
bad_config!(
|
||||||
cp,
|
cp,
|
||||||
"[cache]\n\
|
"[cache]\n\
|
||||||
enabled = true\n\
|
enabled = true\n\
|
||||||
@@ -458,10 +423,8 @@ fn test_duration_settings() {
|
|||||||
optimizing-compression-task-timeout = 333",
|
optimizing-compression-task-timeout = 333",
|
||||||
cd
|
cd
|
||||||
);
|
);
|
||||||
assert!(!conf.enabled());
|
|
||||||
assert!(!conf.errors.is_empty());
|
|
||||||
|
|
||||||
let conf = load_config!(
|
bad_config!(
|
||||||
cp,
|
cp,
|
||||||
"[cache]\n\
|
"[cache]\n\
|
||||||
enabled = true\n\
|
enabled = true\n\
|
||||||
@@ -469,10 +432,8 @@ fn test_duration_settings() {
|
|||||||
optimizing-compression-task-timeout = '10 M'",
|
optimizing-compression-task-timeout = '10 M'",
|
||||||
cd
|
cd
|
||||||
);
|
);
|
||||||
assert!(!conf.enabled());
|
|
||||||
assert!(!conf.errors.is_empty());
|
|
||||||
|
|
||||||
let conf = load_config!(
|
bad_config!(
|
||||||
cp,
|
cp,
|
||||||
"[cache]\n\
|
"[cache]\n\
|
||||||
enabled = true\n\
|
enabled = true\n\
|
||||||
@@ -480,10 +441,8 @@ fn test_duration_settings() {
|
|||||||
optimizing-compression-task-timeout = '10 min'",
|
optimizing-compression-task-timeout = '10 min'",
|
||||||
cd
|
cd
|
||||||
);
|
);
|
||||||
assert!(!conf.enabled());
|
|
||||||
assert!(!conf.errors.is_empty());
|
|
||||||
|
|
||||||
let conf = load_config!(
|
bad_config!(
|
||||||
cp,
|
cp,
|
||||||
"[cache]\n\
|
"[cache]\n\
|
||||||
enabled = true\n\
|
enabled = true\n\
|
||||||
@@ -491,10 +450,8 @@ fn test_duration_settings() {
|
|||||||
optimizing-compression-task-timeout = '-10s'",
|
optimizing-compression-task-timeout = '-10s'",
|
||||||
cd
|
cd
|
||||||
);
|
);
|
||||||
assert!(!conf.enabled());
|
|
||||||
assert!(!conf.errors.is_empty());
|
|
||||||
|
|
||||||
let conf = load_config!(
|
bad_config!(
|
||||||
cp,
|
cp,
|
||||||
"[cache]\n\
|
"[cache]\n\
|
||||||
enabled = true\n\
|
enabled = true\n\
|
||||||
@@ -502,8 +459,6 @@ fn test_duration_settings() {
|
|||||||
optimizing-compression-task-timeout = '1.5m'",
|
optimizing-compression-task-timeout = '1.5m'",
|
||||||
cd
|
cd
|
||||||
);
|
);
|
||||||
assert!(!conf.enabled());
|
|
||||||
assert!(!conf.errors.is_empty());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -519,12 +474,11 @@ fn test_percent_settings() {
|
|||||||
cd
|
cd
|
||||||
);
|
);
|
||||||
assert!(conf.enabled());
|
assert!(conf.enabled());
|
||||||
assert!(conf.errors.is_empty());
|
|
||||||
assert_eq!(conf.file_count_limit_percent_if_deleting(), 62);
|
assert_eq!(conf.file_count_limit_percent_if_deleting(), 62);
|
||||||
assert_eq!(conf.files_total_size_limit_percent_if_deleting(), 23);
|
assert_eq!(conf.files_total_size_limit_percent_if_deleting(), 23);
|
||||||
|
|
||||||
// different errors
|
// different errors
|
||||||
let conf = load_config!(
|
bad_config!(
|
||||||
cp,
|
cp,
|
||||||
"[cache]\n\
|
"[cache]\n\
|
||||||
enabled = true\n\
|
enabled = true\n\
|
||||||
@@ -532,10 +486,8 @@ fn test_percent_settings() {
|
|||||||
files-total-size-limit-percent-if-deleting = '23'",
|
files-total-size-limit-percent-if-deleting = '23'",
|
||||||
cd
|
cd
|
||||||
);
|
);
|
||||||
assert!(!conf.enabled());
|
|
||||||
assert!(!conf.errors.is_empty());
|
|
||||||
|
|
||||||
let conf = load_config!(
|
bad_config!(
|
||||||
cp,
|
cp,
|
||||||
"[cache]\n\
|
"[cache]\n\
|
||||||
enabled = true\n\
|
enabled = true\n\
|
||||||
@@ -543,10 +495,8 @@ fn test_percent_settings() {
|
|||||||
files-total-size-limit-percent-if-deleting = '22.5%'",
|
files-total-size-limit-percent-if-deleting = '22.5%'",
|
||||||
cd
|
cd
|
||||||
);
|
);
|
||||||
assert!(!conf.enabled());
|
|
||||||
assert!(!conf.errors.is_empty());
|
|
||||||
|
|
||||||
let conf = load_config!(
|
bad_config!(
|
||||||
cp,
|
cp,
|
||||||
"[cache]\n\
|
"[cache]\n\
|
||||||
enabled = true\n\
|
enabled = true\n\
|
||||||
@@ -554,10 +504,8 @@ fn test_percent_settings() {
|
|||||||
files-total-size-limit-percent-if-deleting = '0.5'",
|
files-total-size-limit-percent-if-deleting = '0.5'",
|
||||||
cd
|
cd
|
||||||
);
|
);
|
||||||
assert!(!conf.enabled());
|
|
||||||
assert!(!conf.errors.is_empty());
|
|
||||||
|
|
||||||
let conf = load_config!(
|
bad_config!(
|
||||||
cp,
|
cp,
|
||||||
"[cache]\n\
|
"[cache]\n\
|
||||||
enabled = true\n\
|
enabled = true\n\
|
||||||
@@ -565,10 +513,8 @@ fn test_percent_settings() {
|
|||||||
files-total-size-limit-percent-if-deleting = '-1%'",
|
files-total-size-limit-percent-if-deleting = '-1%'",
|
||||||
cd
|
cd
|
||||||
);
|
);
|
||||||
assert!(!conf.enabled());
|
|
||||||
assert!(!conf.errors.is_empty());
|
|
||||||
|
|
||||||
let conf = load_config!(
|
bad_config!(
|
||||||
cp,
|
cp,
|
||||||
"[cache]\n\
|
"[cache]\n\
|
||||||
enabled = true\n\
|
enabled = true\n\
|
||||||
@@ -576,6 +522,4 @@ fn test_percent_settings() {
|
|||||||
files-total-size-limit-percent-if-deleting = '101%'",
|
files-total-size-limit-percent-if-deleting = '101%'",
|
||||||
cd
|
cd
|
||||||
);
|
);
|
||||||
assert!(!conf.enabled());
|
|
||||||
assert!(!conf.errors.is_empty());
|
|
||||||
}
|
}
|
||||||
|
|||||||
13
crates/environ/src/cache/tests.rs
vendored
13
crates/environ/src/cache/tests.rs
vendored
@@ -36,11 +36,9 @@ fn test_cache_init() {
|
|||||||
);
|
);
|
||||||
fs::write(&config_path, config_content).expect("Failed to write test config file");
|
fs::write(&config_path, config_content).expect("Failed to write test config file");
|
||||||
|
|
||||||
let errors = init(true, Some(&config_path), None);
|
let cache_config = CacheConfig::from_file(Some(&config_path)).unwrap();
|
||||||
assert!(errors.is_empty());
|
|
||||||
|
|
||||||
// test if we can use config
|
// test if we can use config
|
||||||
let cache_config = cache_config();
|
|
||||||
assert!(cache_config.enabled());
|
assert!(cache_config.enabled());
|
||||||
// assumption: config init creates cache directory and returns canonicalized path
|
// assumption: config init creates cache directory and returns canonicalized path
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@@ -53,8 +51,7 @@ fn test_cache_init() {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// test if we can use worker
|
// test if we can use worker
|
||||||
let worker = worker();
|
cache_config.worker().on_cache_update_async(config_path);
|
||||||
worker.on_cache_update_async(config_path);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -69,7 +66,6 @@ fn test_write_read_cache() {
|
|||||||
cache_dir
|
cache_dir
|
||||||
);
|
);
|
||||||
assert!(cache_config.enabled());
|
assert!(cache_config.enabled());
|
||||||
let worker = Worker::start_new(&cache_config, None);
|
|
||||||
|
|
||||||
// assumption: config load creates cache directory and returns canonicalized path
|
// assumption: config load creates cache directory and returns canonicalized path
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@@ -102,7 +98,6 @@ fn test_write_read_cache() {
|
|||||||
compiler1,
|
compiler1,
|
||||||
false,
|
false,
|
||||||
&cache_config,
|
&cache_config,
|
||||||
&worker,
|
|
||||||
));
|
));
|
||||||
assert!(entry1.0.is_some());
|
assert!(entry1.0.is_some());
|
||||||
assert!(entry1.get_data().is_none());
|
assert!(entry1.get_data().is_none());
|
||||||
@@ -117,7 +112,6 @@ fn test_write_read_cache() {
|
|||||||
compiler1,
|
compiler1,
|
||||||
false,
|
false,
|
||||||
&cache_config,
|
&cache_config,
|
||||||
&worker,
|
|
||||||
));
|
));
|
||||||
let data2 = new_module_cache_data(&mut rng);
|
let data2 = new_module_cache_data(&mut rng);
|
||||||
entry2.update_data(&data2);
|
entry2.update_data(&data2);
|
||||||
@@ -131,7 +125,6 @@ fn test_write_read_cache() {
|
|||||||
compiler1,
|
compiler1,
|
||||||
false,
|
false,
|
||||||
&cache_config,
|
&cache_config,
|
||||||
&worker,
|
|
||||||
));
|
));
|
||||||
let data3 = new_module_cache_data(&mut rng);
|
let data3 = new_module_cache_data(&mut rng);
|
||||||
entry3.update_data(&data3);
|
entry3.update_data(&data3);
|
||||||
@@ -146,7 +139,6 @@ fn test_write_read_cache() {
|
|||||||
compiler1,
|
compiler1,
|
||||||
false,
|
false,
|
||||||
&cache_config,
|
&cache_config,
|
||||||
&worker,
|
|
||||||
));
|
));
|
||||||
let data4 = new_module_cache_data(&mut rng);
|
let data4 = new_module_cache_data(&mut rng);
|
||||||
entry4.update_data(&data4);
|
entry4.update_data(&data4);
|
||||||
@@ -162,7 +154,6 @@ fn test_write_read_cache() {
|
|||||||
compiler2,
|
compiler2,
|
||||||
false,
|
false,
|
||||||
&cache_config,
|
&cache_config,
|
||||||
&worker,
|
|
||||||
));
|
));
|
||||||
let data5 = new_module_cache_data(&mut rng);
|
let data5 = new_module_cache_data(&mut rng);
|
||||||
entry5.update_data(&data5);
|
entry5.update_data(&data5);
|
||||||
|
|||||||
38
crates/environ/src/cache/worker.rs
vendored
38
crates/environ/src/cache/worker.rs
vendored
@@ -5,16 +5,15 @@
|
|||||||
//! but we guarantee eventual consistency and fault tolerancy.
|
//! but we guarantee eventual consistency and fault tolerancy.
|
||||||
//! Background tasks can be CPU intensive, but the worker thread has low priority.
|
//! Background tasks can be CPU intensive, but the worker thread has low priority.
|
||||||
|
|
||||||
use super::{cache_config, fs_write_atomic, CacheConfig};
|
use super::{fs_write_atomic, CacheConfig};
|
||||||
use log::{debug, info, trace, warn};
|
use log::{debug, info, trace, warn};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use spin::Once;
|
|
||||||
use std::cmp;
|
use std::cmp;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::ffi::OsStr;
|
use std::ffi::OsStr;
|
||||||
|
use std::fmt;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::sync::atomic::{self, AtomicBool};
|
|
||||||
use std::sync::mpsc::{sync_channel, Receiver, SyncSender};
|
use std::sync::mpsc::{sync_channel, Receiver, SyncSender};
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
use std::sync::{Arc, Condvar, Mutex};
|
use std::sync::{Arc, Condvar, Mutex};
|
||||||
@@ -25,6 +24,7 @@ use std::time::SystemTime;
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
use tests::system_time_stub::SystemTimeStub as SystemTime;
|
use tests::system_time_stub::SystemTimeStub as SystemTime;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
pub(super) struct Worker {
|
pub(super) struct Worker {
|
||||||
sender: SyncSender<CacheEvent>,
|
sender: SyncSender<CacheEvent>,
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
@@ -46,29 +46,6 @@ struct WorkerStats {
|
|||||||
handled: u32,
|
handled: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
static WORKER: Once<Worker> = Once::new();
|
|
||||||
static INIT_CALLED: AtomicBool = AtomicBool::new(false);
|
|
||||||
|
|
||||||
pub(super) fn worker() -> &'static Worker {
|
|
||||||
WORKER
|
|
||||||
.r#try()
|
|
||||||
.expect("Cache worker must be initialized before usage")
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(super) fn init(init_file_per_thread_logger: Option<&'static str>) {
|
|
||||||
INIT_CALLED
|
|
||||||
.compare_exchange(
|
|
||||||
false,
|
|
||||||
true,
|
|
||||||
atomic::Ordering::SeqCst,
|
|
||||||
atomic::Ordering::SeqCst,
|
|
||||||
)
|
|
||||||
.expect("Cache worker init must be called at most once");
|
|
||||||
|
|
||||||
let worker = Worker::start_new(cache_config(), init_file_per_thread_logger);
|
|
||||||
WORKER.call_once(|| worker);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
enum CacheEvent {
|
enum CacheEvent {
|
||||||
OnCacheGet(PathBuf),
|
OnCacheGet(PathBuf),
|
||||||
@@ -168,6 +145,12 @@ impl Worker {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl fmt::Debug for Worker {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
f.debug_struct("Worker").finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
struct ModuleCacheStatistics {
|
struct ModuleCacheStatistics {
|
||||||
pub usages: u64,
|
pub usages: u64,
|
||||||
@@ -210,9 +193,6 @@ macro_rules! unwrap_or_warn {
|
|||||||
|
|
||||||
impl WorkerThread {
|
impl WorkerThread {
|
||||||
fn run(self, init_file_per_thread_logger: Option<&'static str>) {
|
fn run(self, init_file_per_thread_logger: Option<&'static str>) {
|
||||||
#[cfg(not(test))] // We want to test the worker without relying on init() being called
|
|
||||||
assert!(INIT_CALLED.load(atomic::Ordering::SeqCst));
|
|
||||||
|
|
||||||
if let Some(prefix) = init_file_per_thread_logger {
|
if let Some(prefix) = init_file_per_thread_logger {
|
||||||
file_per_thread_logger::initialize(prefix);
|
file_per_thread_logger::initialize(prefix);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
use crate::cache::ModuleCacheDataTupleType;
|
use crate::cache::ModuleCacheDataTupleType;
|
||||||
use crate::module;
|
use crate::module;
|
||||||
use crate::module_environ::FunctionBodyData;
|
use crate::module_environ::FunctionBodyData;
|
||||||
|
use crate::CacheConfig;
|
||||||
use cranelift_codegen::{binemit, ir, isa, Context};
|
use cranelift_codegen::{binemit, ir, isa, Context};
|
||||||
use cranelift_entity::PrimaryMap;
|
use cranelift_entity::PrimaryMap;
|
||||||
use cranelift_wasm::{DefinedFuncIndex, FuncIndex, ModuleTranslationState, WasmError};
|
use cranelift_wasm::{DefinedFuncIndex, FuncIndex, ModuleTranslationState, WasmError};
|
||||||
@@ -300,5 +301,6 @@ pub trait Compiler {
|
|||||||
function_body_inputs: PrimaryMap<DefinedFuncIndex, FunctionBodyData<'data>>,
|
function_body_inputs: PrimaryMap<DefinedFuncIndex, FunctionBodyData<'data>>,
|
||||||
isa: &dyn isa::TargetIsa,
|
isa: &dyn isa::TargetIsa,
|
||||||
generate_debug_info: bool,
|
generate_debug_info: bool,
|
||||||
|
cache_config: &CacheConfig,
|
||||||
) -> Result<ModuleCacheDataTupleType, CompileError>;
|
) -> Result<ModuleCacheDataTupleType, CompileError>;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ use crate::func_environ::{
|
|||||||
};
|
};
|
||||||
use crate::module::Module;
|
use crate::module::Module;
|
||||||
use crate::module_environ::FunctionBodyData;
|
use crate::module_environ::FunctionBodyData;
|
||||||
|
use crate::CacheConfig;
|
||||||
use cranelift_codegen::ir::{self, ExternalName};
|
use cranelift_codegen::ir::{self, ExternalName};
|
||||||
use cranelift_codegen::print_errors::pretty_error;
|
use cranelift_codegen::print_errors::pretty_error;
|
||||||
use cranelift_codegen::{binemit, isa, Context};
|
use cranelift_codegen::{binemit, isa, Context};
|
||||||
@@ -176,6 +177,7 @@ impl crate::compilation::Compiler for Cranelift {
|
|||||||
function_body_inputs: PrimaryMap<DefinedFuncIndex, FunctionBodyData<'data>>,
|
function_body_inputs: PrimaryMap<DefinedFuncIndex, FunctionBodyData<'data>>,
|
||||||
isa: &dyn isa::TargetIsa,
|
isa: &dyn isa::TargetIsa,
|
||||||
generate_debug_info: bool,
|
generate_debug_info: bool,
|
||||||
|
cache_config: &CacheConfig,
|
||||||
) -> Result<ModuleCacheDataTupleType, CompileError> {
|
) -> Result<ModuleCacheDataTupleType, CompileError> {
|
||||||
let cache_entry = ModuleCacheEntry::new(
|
let cache_entry = ModuleCacheEntry::new(
|
||||||
module,
|
module,
|
||||||
@@ -183,6 +185,7 @@ impl crate::compilation::Compiler for Cranelift {
|
|||||||
isa,
|
isa,
|
||||||
"cranelift",
|
"cranelift",
|
||||||
generate_debug_info,
|
generate_debug_info,
|
||||||
|
cache_config,
|
||||||
);
|
);
|
||||||
|
|
||||||
let data = match cache_entry.get_data() {
|
let data = match cache_entry.get_data() {
|
||||||
|
|||||||
@@ -43,7 +43,8 @@ pub use crate::address_map::{
|
|||||||
FunctionAddressMap, InstructionAddressMap, ModuleAddressMap, ModuleMemoryOffset,
|
FunctionAddressMap, InstructionAddressMap, ModuleAddressMap, ModuleMemoryOffset,
|
||||||
ModuleVmctxInfo, ValueLabelsRanges,
|
ModuleVmctxInfo, ValueLabelsRanges,
|
||||||
};
|
};
|
||||||
pub use crate::cache::{create_new_config as cache_create_new_config, init as cache_init};
|
pub use crate::cache::create_new_config as cache_create_new_config;
|
||||||
|
pub use crate::cache::CacheConfig;
|
||||||
pub use crate::compilation::{
|
pub use crate::compilation::{
|
||||||
Compilation, CompileError, CompiledFunction, CompiledFunctionUnwindInfo,
|
Compilation, CompileError, CompiledFunction, CompiledFunctionUnwindInfo,
|
||||||
CompiledFunctionUnwindInfoReloc, Compiler, Relocation, RelocationTarget, Relocations,
|
CompiledFunctionUnwindInfoReloc, Compiler, Relocation, RelocationTarget, Relocations,
|
||||||
|
|||||||
@@ -1,14 +1,15 @@
|
|||||||
//! Support for compiling with Lightbeam.
|
//! Support for compiling with Lightbeam.
|
||||||
|
|
||||||
use crate::cache::ModuleCacheDataTupleType;
|
use crate::cache::ModuleCacheDataTupleType;
|
||||||
use crate::compilation::{Compilation, CompileError, Relocations, Traps};
|
use crate::compilation::{Compilation, CompileError, Traps};
|
||||||
use crate::func_environ::FuncEnvironment;
|
use crate::func_environ::FuncEnvironment;
|
||||||
use crate::module::Module;
|
use crate::module::Module;
|
||||||
use crate::module_environ::FunctionBodyData;
|
use crate::module_environ::FunctionBodyData;
|
||||||
// TODO: Put this in `compilation`
|
// TODO: Put this in `compilation`
|
||||||
use crate::address_map::{ModuleAddressMap, ValueLabelsRanges};
|
use crate::address_map::{ModuleAddressMap, ValueLabelsRanges};
|
||||||
use crate::cranelift::RelocSink;
|
use crate::cranelift::RelocSink;
|
||||||
use cranelift_codegen::{ir, isa};
|
use crate::CacheConfig;
|
||||||
|
use cranelift_codegen::isa;
|
||||||
use cranelift_entity::{PrimaryMap, SecondaryMap};
|
use cranelift_entity::{PrimaryMap, SecondaryMap};
|
||||||
use cranelift_wasm::{DefinedFuncIndex, ModuleTranslationState};
|
use cranelift_wasm::{DefinedFuncIndex, ModuleTranslationState};
|
||||||
|
|
||||||
@@ -25,6 +26,7 @@ impl crate::compilation::Compiler for Lightbeam {
|
|||||||
isa: &dyn isa::TargetIsa,
|
isa: &dyn isa::TargetIsa,
|
||||||
// TODO
|
// TODO
|
||||||
generate_debug_info: bool,
|
generate_debug_info: bool,
|
||||||
|
_cache_config: &CacheConfig,
|
||||||
) -> Result<ModuleCacheDataTupleType, CompileError> {
|
) -> Result<ModuleCacheDataTupleType, CompileError> {
|
||||||
if generate_debug_info {
|
if generate_debug_info {
|
||||||
return Err(CompileError::DebugInfoNotSupported);
|
return Err(CompileError::DebugInfoNotSupported);
|
||||||
|
|||||||
@@ -1,10 +0,0 @@
|
|||||||
use wasmtime_environ::cache_init;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_cache_default_config_in_memory() {
|
|
||||||
let errors = cache_init::<&str>(true, None, None);
|
|
||||||
assert!(
|
|
||||||
errors.is_empty(),
|
|
||||||
"This test loads config from the default location, if there's one. Make sure it's correct!"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
use wasmtime_environ::cache_init;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_cache_disabled() {
|
|
||||||
let errors = cache_init::<&str>(false, None, None);
|
|
||||||
assert!(errors.is_empty(), "Failed to disable cache system");
|
|
||||||
}
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
use std::fs;
|
|
||||||
use tempfile;
|
|
||||||
use wasmtime_environ::cache_init;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
#[should_panic]
|
|
||||||
fn test_cache_fail_calling_init_twice() {
|
|
||||||
let dir = tempfile::tempdir().expect("Can't create temporary directory");
|
|
||||||
let cache_dir = dir.path().join("cache-dir");
|
|
||||||
let baseline_compression_level = 5;
|
|
||||||
|
|
||||||
let config_path = dir.path().join("cache-config.toml");
|
|
||||||
let config_content = format!(
|
|
||||||
"[cache]\n\
|
|
||||||
enabled = true\n\
|
|
||||||
directory = {}\n\
|
|
||||||
baseline-compression-level = {}\n",
|
|
||||||
toml::to_string_pretty(&format!("{}", cache_dir.display())).unwrap(),
|
|
||||||
baseline_compression_level,
|
|
||||||
);
|
|
||||||
fs::write(&config_path, config_content).expect("Failed to write test config file");
|
|
||||||
|
|
||||||
let errors = cache_init(true, Some(&config_path), None);
|
|
||||||
assert!(errors.is_empty());
|
|
||||||
let _errors = cache_init(true, Some(&config_path), None);
|
|
||||||
}
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
use std::fs;
|
|
||||||
use tempfile;
|
|
||||||
use wasmtime_environ::cache_init;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_cache_fail_invalid_config() {
|
|
||||||
let dir = tempfile::tempdir().expect("Can't create temporary directory");
|
|
||||||
let baseline_compression_level = -4;
|
|
||||||
|
|
||||||
let config_path = dir.path().join("cache-config.toml");
|
|
||||||
let config_content = format!(
|
|
||||||
"[cache]\n\
|
|
||||||
enabled = true\n\
|
|
||||||
directory = {}\n\
|
|
||||||
baseline-compression-level = {}\n",
|
|
||||||
toml::to_string_pretty(&format!("{}", config_path.display())).unwrap(), // directory is a file -- incorrect!
|
|
||||||
baseline_compression_level,
|
|
||||||
);
|
|
||||||
fs::write(&config_path, config_content).expect("Failed to write test config file");
|
|
||||||
|
|
||||||
let errors = cache_init(true, Some(&config_path), None);
|
|
||||||
assert!(!errors.is_empty());
|
|
||||||
}
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
use tempfile;
|
|
||||||
use wasmtime_environ::cache_init;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_cache_fail_invalid_path_to_config() {
|
|
||||||
let dir = tempfile::tempdir().expect("Can't create temporary directory");
|
|
||||||
let config_path = dir.path().join("cache-config.toml"); // doesn't exist
|
|
||||||
let errors = cache_init(true, Some(&config_path), None);
|
|
||||||
assert!(!errors.is_empty());
|
|
||||||
}
|
|
||||||
@@ -16,9 +16,9 @@ use wasmtime_environ::entity::{EntityRef, PrimaryMap};
|
|||||||
use wasmtime_environ::isa::{TargetFrontendConfig, TargetIsa};
|
use wasmtime_environ::isa::{TargetFrontendConfig, TargetIsa};
|
||||||
use wasmtime_environ::wasm::{DefinedFuncIndex, DefinedMemoryIndex, MemoryIndex};
|
use wasmtime_environ::wasm::{DefinedFuncIndex, DefinedMemoryIndex, MemoryIndex};
|
||||||
use wasmtime_environ::{
|
use wasmtime_environ::{
|
||||||
Compilation, CompileError, CompiledFunction, CompiledFunctionUnwindInfo, Compiler as _C,
|
CacheConfig, Compilation, CompileError, CompiledFunction, CompiledFunctionUnwindInfo,
|
||||||
FunctionBodyData, Module, ModuleMemoryOffset, ModuleVmctxInfo, Relocations, Traps, Tunables,
|
Compiler as _C, FunctionBodyData, Module, ModuleMemoryOffset, ModuleVmctxInfo, Relocations,
|
||||||
VMOffsets,
|
Traps, Tunables, VMOffsets,
|
||||||
};
|
};
|
||||||
use wasmtime_runtime::{
|
use wasmtime_runtime::{
|
||||||
jit_function_registry, InstantiationError, SignatureRegistry, TrapRegistration, TrapRegistry,
|
jit_function_registry, InstantiationError, SignatureRegistry, TrapRegistration, TrapRegistry,
|
||||||
@@ -56,6 +56,7 @@ pub struct Compiler {
|
|||||||
trampoline_park: HashMap<*const VMFunctionBody, *const VMFunctionBody>,
|
trampoline_park: HashMap<*const VMFunctionBody, *const VMFunctionBody>,
|
||||||
signatures: SignatureRegistry,
|
signatures: SignatureRegistry,
|
||||||
strategy: CompilationStrategy,
|
strategy: CompilationStrategy,
|
||||||
|
cache_config: CacheConfig,
|
||||||
|
|
||||||
/// The `FunctionBuilderContext`, shared between trampline function compilations.
|
/// The `FunctionBuilderContext`, shared between trampline function compilations.
|
||||||
fn_builder_ctx: FunctionBuilderContext,
|
fn_builder_ctx: FunctionBuilderContext,
|
||||||
@@ -63,7 +64,11 @@ pub struct Compiler {
|
|||||||
|
|
||||||
impl Compiler {
|
impl Compiler {
|
||||||
/// Construct a new `Compiler`.
|
/// Construct a new `Compiler`.
|
||||||
pub fn new(isa: Box<dyn TargetIsa>, strategy: CompilationStrategy) -> Self {
|
pub fn new(
|
||||||
|
isa: Box<dyn TargetIsa>,
|
||||||
|
strategy: CompilationStrategy,
|
||||||
|
cache_config: CacheConfig,
|
||||||
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
isa,
|
isa,
|
||||||
code_memory: CodeMemory::new(),
|
code_memory: CodeMemory::new(),
|
||||||
@@ -73,6 +78,7 @@ impl Compiler {
|
|||||||
fn_builder_ctx: FunctionBuilderContext::new(),
|
fn_builder_ctx: FunctionBuilderContext::new(),
|
||||||
strategy,
|
strategy,
|
||||||
trap_registry: TrapRegistry::default(),
|
trap_registry: TrapRegistry::default(),
|
||||||
|
cache_config,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -124,6 +130,7 @@ impl Compiler {
|
|||||||
function_body_inputs,
|
function_body_inputs,
|
||||||
&*self.isa,
|
&*self.isa,
|
||||||
debug_data.is_some(),
|
debug_data.is_some(),
|
||||||
|
&self.cache_config,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
#[cfg(feature = "lightbeam")]
|
#[cfg(feature = "lightbeam")]
|
||||||
@@ -134,6 +141,7 @@ impl Compiler {
|
|||||||
function_body_inputs,
|
function_body_inputs,
|
||||||
&*self.isa,
|
&*self.isa,
|
||||||
debug_data.is_some(),
|
debug_data.is_some(),
|
||||||
|
&self.cache_config,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
use crate::action::{get, inspect_memory, invoke};
|
use crate::action::{get, inspect_memory, invoke};
|
||||||
use crate::{
|
use crate::{
|
||||||
instantiate, ActionError, ActionOutcome, CompilationStrategy, CompiledModule, Compiler,
|
instantiate, ActionError, ActionOutcome, CompiledModule, Compiler, InstanceHandle, Namespace,
|
||||||
InstanceHandle, Namespace, RuntimeValue, SetupError,
|
RuntimeValue, SetupError,
|
||||||
};
|
};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
use wasmparser::{validate, OperatorValidatorConfig, ValidatingParserConfig};
|
use wasmparser::{validate, OperatorValidatorConfig, ValidatingParserConfig};
|
||||||
use wasmtime_environ::isa::TargetIsa;
|
|
||||||
|
|
||||||
/// Indicates an unknown instance was specified.
|
/// Indicates an unknown instance was specified.
|
||||||
#[derive(Error, Debug)]
|
#[derive(Error, Debug)]
|
||||||
@@ -83,11 +82,6 @@ impl Context {
|
|||||||
self.debug_info = value;
|
self.debug_info = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Construct a new instance of `Context` with the given target.
|
|
||||||
pub fn with_isa(isa: Box<dyn TargetIsa>, strategy: CompilationStrategy) -> Self {
|
|
||||||
Self::new(Box::new(Compiler::new(isa, strategy)))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Retrieve the context features
|
/// Retrieve the context features
|
||||||
pub fn features(&self) -> &Features {
|
pub fn features(&self) -> &Features {
|
||||||
&self.features
|
&self.features
|
||||||
|
|||||||
@@ -4,14 +4,12 @@ use crate::{init_file_per_thread_logger, pick_compilation_strategy, CommonOption
|
|||||||
use anyhow::{bail, Context as _, Result};
|
use anyhow::{bail, Context as _, Result};
|
||||||
use std::{
|
use std::{
|
||||||
ffi::{OsStr, OsString},
|
ffi::{OsStr, OsString},
|
||||||
fmt::Write,
|
|
||||||
fs::File,
|
fs::File,
|
||||||
path::{Component, Path, PathBuf},
|
path::{Component, Path, PathBuf},
|
||||||
};
|
};
|
||||||
use structopt::{clap::AppSettings, StructOpt};
|
use structopt::{clap::AppSettings, StructOpt};
|
||||||
use wasi_common::preopen_dir;
|
use wasi_common::preopen_dir;
|
||||||
use wasmtime::{Config, Engine, Instance, Module, Store};
|
use wasmtime::{Config, Engine, Instance, Module, Store};
|
||||||
use wasmtime_environ::cache_init;
|
|
||||||
use wasmtime_interface_types::ModuleData;
|
use wasmtime_interface_types::ModuleData;
|
||||||
use wasmtime_wasi::{old::snapshot_0::Wasi as WasiSnapshot0, Wasi};
|
use wasmtime_wasi::{old::snapshot_0::Wasi as WasiSnapshot0, Wasi};
|
||||||
|
|
||||||
@@ -91,28 +89,11 @@ pub struct RunCommand {
|
|||||||
impl RunCommand {
|
impl RunCommand {
|
||||||
/// Executes the command.
|
/// Executes the command.
|
||||||
pub fn execute(&self) -> Result<()> {
|
pub fn execute(&self) -> Result<()> {
|
||||||
let log_config = if self.common.debug {
|
if self.common.debug {
|
||||||
pretty_env_logger::init();
|
pretty_env_logger::init();
|
||||||
None
|
|
||||||
} else {
|
} else {
|
||||||
let prefix = "wasmtime.dbg.";
|
let prefix = "wasmtime.dbg.";
|
||||||
init_file_per_thread_logger(prefix);
|
init_file_per_thread_logger(prefix);
|
||||||
Some(prefix)
|
|
||||||
};
|
|
||||||
|
|
||||||
let errors = cache_init(
|
|
||||||
!self.common.disable_cache,
|
|
||||||
self.common.config.as_ref(),
|
|
||||||
log_config,
|
|
||||||
);
|
|
||||||
|
|
||||||
if !errors.is_empty() {
|
|
||||||
let mut message = String::new();
|
|
||||||
writeln!(message, "Cache initialization failed. Errors:")?;
|
|
||||||
for e in errors {
|
|
||||||
writeln!(message, " -> {}", e)?;
|
|
||||||
}
|
|
||||||
bail!(message);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut config = Config::new();
|
let mut config = Config::new();
|
||||||
@@ -124,6 +105,7 @@ impl RunCommand {
|
|||||||
self.common.cranelift,
|
self.common.cranelift,
|
||||||
self.common.lightbeam,
|
self.common.lightbeam,
|
||||||
)?)?;
|
)?)?;
|
||||||
|
self.common.configure_cache(&mut config)?;
|
||||||
|
|
||||||
if self.common.optimize {
|
if self.common.optimize {
|
||||||
config.cranelift_opt_level(wasmtime::OptLevel::Speed);
|
config.cranelift_opt_level(wasmtime::OptLevel::Speed);
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ use crate::{init_file_per_thread_logger, pick_compilation_strategy, CommonOption
|
|||||||
use anyhow::{anyhow, bail, Context as _, Result};
|
use anyhow::{anyhow, bail, Context as _, Result};
|
||||||
use faerie::Artifact;
|
use faerie::Artifact;
|
||||||
use std::{
|
use std::{
|
||||||
fmt::Write,
|
|
||||||
fs::File,
|
fs::File,
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
str::FromStr,
|
str::FromStr,
|
||||||
@@ -16,9 +15,9 @@ use wasmtime_debug::{emit_debugsections, read_debuginfo};
|
|||||||
#[cfg(feature = "lightbeam")]
|
#[cfg(feature = "lightbeam")]
|
||||||
use wasmtime_environ::Lightbeam;
|
use wasmtime_environ::Lightbeam;
|
||||||
use wasmtime_environ::{
|
use wasmtime_environ::{
|
||||||
cache_init, entity::EntityRef, settings, settings::Configurable, wasm::DefinedMemoryIndex,
|
entity::EntityRef, settings, settings::Configurable, wasm::DefinedMemoryIndex,
|
||||||
wasm::MemoryIndex, Compiler, Cranelift, ModuleEnvironment, ModuleMemoryOffset, ModuleVmctxInfo,
|
wasm::MemoryIndex, CacheConfig, Compiler, Cranelift, ModuleEnvironment, ModuleMemoryOffset,
|
||||||
Tunables, VMOffsets,
|
ModuleVmctxInfo, Tunables, VMOffsets,
|
||||||
};
|
};
|
||||||
use wasmtime_jit::native;
|
use wasmtime_jit::native;
|
||||||
use wasmtime_obj::emit_module;
|
use wasmtime_obj::emit_module;
|
||||||
@@ -59,34 +58,22 @@ pub struct WasmToObjCommand {
|
|||||||
impl WasmToObjCommand {
|
impl WasmToObjCommand {
|
||||||
/// Executes the command.
|
/// Executes the command.
|
||||||
pub fn execute(&self) -> Result<()> {
|
pub fn execute(&self) -> Result<()> {
|
||||||
let log_config = if self.common.debug {
|
|
||||||
pretty_env_logger::init();
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
let prefix = "wasm2obj.dbg.";
|
|
||||||
init_file_per_thread_logger(prefix);
|
|
||||||
Some(prefix)
|
|
||||||
};
|
|
||||||
|
|
||||||
let errors = cache_init(
|
|
||||||
!self.common.disable_cache,
|
|
||||||
self.common.config.as_ref(),
|
|
||||||
log_config,
|
|
||||||
);
|
|
||||||
|
|
||||||
if !errors.is_empty() {
|
|
||||||
let mut message = String::new();
|
|
||||||
writeln!(message, "Cache initialization failed. Errors:")?;
|
|
||||||
for e in errors {
|
|
||||||
writeln!(message, " -> {}", e)?;
|
|
||||||
}
|
|
||||||
bail!(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
self.handle_module()
|
self.handle_module()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_module(&self) -> Result<()> {
|
fn handle_module(&self) -> Result<()> {
|
||||||
|
if self.common.debug {
|
||||||
|
pretty_env_logger::init();
|
||||||
|
} else {
|
||||||
|
let prefix = "wasm2obj.dbg.";
|
||||||
|
init_file_per_thread_logger(prefix);
|
||||||
|
}
|
||||||
|
|
||||||
|
let cache_config = if self.common.disable_cache {
|
||||||
|
CacheConfig::new_cache_disabled()
|
||||||
|
} else {
|
||||||
|
CacheConfig::from_file(self.common.config.as_deref())?
|
||||||
|
};
|
||||||
let strategy = pick_compilation_strategy(self.common.cranelift, self.common.lightbeam)?;
|
let strategy = pick_compilation_strategy(self.common.cranelift, self.common.lightbeam)?;
|
||||||
|
|
||||||
let data = wat::parse_file(&self.module).context("failed to parse module")?;
|
let data = wat::parse_file(&self.module).context("failed to parse module")?;
|
||||||
@@ -147,6 +134,7 @@ impl WasmToObjCommand {
|
|||||||
lazy_function_body_inputs,
|
lazy_function_body_inputs,
|
||||||
&*isa,
|
&*isa,
|
||||||
self.common.debug_info,
|
self.common.debug_info,
|
||||||
|
&cache_config,
|
||||||
),
|
),
|
||||||
#[cfg(feature = "lightbeam")]
|
#[cfg(feature = "lightbeam")]
|
||||||
Strategy::Lightbeam => Lightbeam::compile_module(
|
Strategy::Lightbeam => Lightbeam::compile_module(
|
||||||
@@ -155,6 +143,7 @@ impl WasmToObjCommand {
|
|||||||
lazy_function_body_inputs,
|
lazy_function_body_inputs,
|
||||||
&*isa,
|
&*isa,
|
||||||
self.common.debug_info,
|
self.common.debug_info,
|
||||||
|
&cache_config,
|
||||||
),
|
),
|
||||||
#[cfg(not(feature = "lightbeam"))]
|
#[cfg(not(feature = "lightbeam"))]
|
||||||
Strategy::Lightbeam => bail!("lightbeam support not enabled"),
|
Strategy::Lightbeam => bail!("lightbeam support not enabled"),
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
//! The module that implements the `wasmtime wast` command.
|
//! The module that implements the `wasmtime wast` command.
|
||||||
|
|
||||||
use crate::{init_file_per_thread_logger, pick_compilation_strategy, CommonOptions};
|
use crate::{init_file_per_thread_logger, pick_compilation_strategy, CommonOptions};
|
||||||
use anyhow::{bail, Context as _, Result};
|
use anyhow::{Context as _, Result};
|
||||||
use std::{fmt::Write, path::PathBuf};
|
use std::path::PathBuf;
|
||||||
use structopt::{clap::AppSettings, StructOpt};
|
use structopt::{clap::AppSettings, StructOpt};
|
||||||
use wasmtime::{Config, Engine, Store};
|
use wasmtime::{Config, Engine, Store};
|
||||||
use wasmtime_environ::cache_init;
|
|
||||||
use wasmtime_wast::WastContext;
|
use wasmtime_wast::WastContext;
|
||||||
|
|
||||||
/// Runs a WebAssembly test script file
|
/// Runs a WebAssembly test script file
|
||||||
@@ -27,28 +26,11 @@ pub struct WastCommand {
|
|||||||
impl WastCommand {
|
impl WastCommand {
|
||||||
/// Executes the command.
|
/// Executes the command.
|
||||||
pub fn execute(&self) -> Result<()> {
|
pub fn execute(&self) -> Result<()> {
|
||||||
let log_config = if self.common.debug {
|
if self.common.debug {
|
||||||
pretty_env_logger::init();
|
pretty_env_logger::init();
|
||||||
None
|
|
||||||
} else {
|
} else {
|
||||||
let prefix = "wast.dbg.";
|
let prefix = "wast.dbg.";
|
||||||
init_file_per_thread_logger(prefix);
|
init_file_per_thread_logger(prefix);
|
||||||
Some(prefix)
|
|
||||||
};
|
|
||||||
|
|
||||||
let errors = cache_init(
|
|
||||||
!self.common.disable_cache,
|
|
||||||
self.common.config.as_ref(),
|
|
||||||
log_config,
|
|
||||||
);
|
|
||||||
|
|
||||||
if !errors.is_empty() {
|
|
||||||
let mut message = String::new();
|
|
||||||
writeln!(message, "Cache initialization failed. Errors:")?;
|
|
||||||
for e in errors {
|
|
||||||
writeln!(message, " -> {}", e)?;
|
|
||||||
}
|
|
||||||
bail!(message);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut config = Config::new();
|
let mut config = Config::new();
|
||||||
@@ -60,6 +42,7 @@ impl WastCommand {
|
|||||||
self.common.cranelift,
|
self.common.cranelift,
|
||||||
self.common.lightbeam,
|
self.common.lightbeam,
|
||||||
)?)?;
|
)?)?;
|
||||||
|
self.common.configure_cache(&mut config)?;
|
||||||
|
|
||||||
if self.common.optimize {
|
if self.common.optimize {
|
||||||
config.cranelift_opt_level(wasmtime::OptLevel::Speed);
|
config.cranelift_opt_level(wasmtime::OptLevel::Speed);
|
||||||
|
|||||||
19
src/lib.rs
19
src/lib.rs
@@ -29,7 +29,7 @@ pub mod commands;
|
|||||||
use anyhow::{bail, Result};
|
use anyhow::{bail, Result};
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use structopt::StructOpt;
|
use structopt::StructOpt;
|
||||||
use wasmtime::Strategy;
|
use wasmtime::{Config, Strategy};
|
||||||
|
|
||||||
fn pick_compilation_strategy(cranelift: bool, lightbeam: bool) -> Result<Strategy> {
|
fn pick_compilation_strategy(cranelift: bool, lightbeam: bool) -> Result<Strategy> {
|
||||||
Ok(match (lightbeam, cranelift) {
|
Ok(match (lightbeam, cranelift) {
|
||||||
@@ -101,3 +101,20 @@ struct CommonOptions {
|
|||||||
#[structopt(short = "O", long)]
|
#[structopt(short = "O", long)]
|
||||||
optimize: bool,
|
optimize: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl CommonOptions {
|
||||||
|
fn configure_cache(&self, config: &mut Config) -> Result<()> {
|
||||||
|
if self.disable_cache {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
match &self.config {
|
||||||
|
Some(path) => {
|
||||||
|
config.cache_config_load(path)?;
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
config.cache_config_load_default()?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ use more_asserts::assert_gt;
|
|||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use wasmtime_environ::settings;
|
use wasmtime_environ::settings;
|
||||||
use wasmtime_environ::settings::Configurable;
|
use wasmtime_environ::settings::Configurable;
|
||||||
|
use wasmtime_environ::CacheConfig;
|
||||||
use wasmtime_jit::{instantiate, native, CompilationStrategy, Compiler, NullResolver};
|
use wasmtime_jit::{instantiate, native, CompilationStrategy, Compiler, NullResolver};
|
||||||
|
|
||||||
const PATH_MODULE_RS2WASM_ADD_FUNC: &str = r"tests/wat/rs2wasm-add-func.wat";
|
const PATH_MODULE_RS2WASM_ADD_FUNC: &str = r"tests/wat/rs2wasm-add-func.wat";
|
||||||
@@ -20,7 +21,8 @@ fn test_environ_translate() {
|
|||||||
let isa = isa_builder.finish(settings::Flags::new(flag_builder));
|
let isa = isa_builder.finish(settings::Flags::new(flag_builder));
|
||||||
|
|
||||||
let mut resolver = NullResolver {};
|
let mut resolver = NullResolver {};
|
||||||
let mut compiler = Compiler::new(isa, CompilationStrategy::Auto);
|
let cache_config = CacheConfig::new_cache_disabled();
|
||||||
|
let mut compiler = Compiler::new(isa, CompilationStrategy::Auto, cache_config);
|
||||||
unsafe {
|
unsafe {
|
||||||
let instance = instantiate(&mut compiler, &data, &mut resolver, false);
|
let instance = instantiate(&mut compiler, &data, &mut resolver, false);
|
||||||
assert!(instance.is_ok());
|
assert!(instance.is_ok());
|
||||||
|
|||||||
Reference in New Issue
Block a user