diff --git a/Cargo.lock b/Cargo.lock index ab6558fe85..f327920bd0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -388,6 +388,7 @@ dependencies = [ "crc32fast", "criterion", "enumset", + "glob", "hex", "hex-literal", "leb128", @@ -892,6 +893,12 @@ dependencies = [ "stable_deref_trait", ] +[[package]] +name = "glob" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" + [[package]] name = "group" version = "0.12.0" diff --git a/packages/vm/Cargo.toml b/packages/vm/Cargo.toml index d7f1a815fd..74a5ac1a00 100644 --- a/packages/vm/Cargo.toml +++ b/packages/vm/Cargo.toml @@ -65,6 +65,7 @@ bitflags = "1.1.0" # https://github.com/CensoredUsername/dynasm-rs/pull/74 [dev-dependencies] criterion = { version = "0.4", features = [ "html_reports" ] } +glob = "0.3.1" hex-literal = "0.3.1" tempfile = "3.1.0" wat = "1.0" diff --git a/packages/vm/src/modules/file_system_cache.rs b/packages/vm/src/modules/file_system_cache.rs index bcf13b737c..8500becce3 100644 --- a/packages/vm/src/modules/file_system_cache.rs +++ b/packages/vm/src/modules/file_system_cache.rs @@ -45,10 +45,7 @@ const MODULE_SERIALIZATION_VERSION: &str = "v4"; /// Representation of a directory that contains compiled Wasm artifacts. pub struct FileSystemCache { - /// The base path this cache operates in. Within this path, versioned directories are created. - /// A sophisticated version of this cache might be able to read multiple input versions in the future. - base_path: PathBuf, - wasmer_module_version: u32, + modules_path: PathBuf, } /// An error type that hides system specific error information @@ -73,19 +70,20 @@ impl FileSystemCache { /// /// 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(path: impl Into) -> Result { - let wasmer_module_version = current_wasmer_module_version(); - - let path: PathBuf = path.into(); - if path.exists() { - let metadata = path + pub unsafe fn new(base_path: impl Into) -> Result { + let base_path: PathBuf = base_path.into(); + if base_path.exists() { + let metadata = base_path .metadata() .map_err(|_e| NewFileSystemCacheError::CouldntGetMetadata)?; if metadata.is_dir() { if !metadata.permissions().readonly() { Ok(Self { - base_path: path, - wasmer_module_version, + modules_path: modules_path( + &base_path, + current_wasmer_module_version(), + &Target::default(), + ), }) } else { Err(NewFileSystemCacheError::ReadonlyPath) @@ -95,10 +93,13 @@ impl FileSystemCache { } } else { // Create the directory and any parent directories if they don't yet exist. - mkdir_p(&path).map_err(|_e| NewFileSystemCacheError::CouldntCreatePath)?; + mkdir_p(&base_path).map_err(|_e| NewFileSystemCacheError::CouldntCreatePath)?; Ok(Self { - base_path: path, - wasmer_module_version, + modules_path: modules_path( + &base_path, + current_wasmer_module_version(), + &Target::default(), + ), }) } } @@ -107,7 +108,7 @@ impl FileSystemCache { /// along with the size of the serialized module. pub fn load(&self, checksum: &Checksum, store: &Store) -> VmResult> { let filename = checksum.to_hex(); - let file_path = self.latest_modules_path().join(filename); + let file_path = self.modules_path.join(filename); let result = unsafe { Module::deserialize_from_file(store, &file_path) }; match result { @@ -133,12 +134,11 @@ impl FileSystemCache { /// The serialized module size is a good approximation (~100.06 %) of the in-memory module size. /// It should not be considered as the exact in-memory module size. pub fn store(&mut self, checksum: &Checksum, module: &Module) -> VmResult { - let modules_dir = self.latest_modules_path(); - mkdir_p(&modules_dir) + mkdir_p(&self.modules_path) .map_err(|_e| VmError::cache_err("Error creating modules directory"))?; let filename = checksum.to_hex(); - let path = modules_dir.join(filename); + let path = self.modules_path.join(filename); module .serialize_to_file(&path) .map_err(|e| VmError::cache_err(format!("Error writing module to disk: {}", e)))?; @@ -151,7 +151,7 @@ impl FileSystemCache { /// Returns true if the file existed and false if the file did not exist. pub fn remove(&mut self, checksum: &Checksum) -> VmResult { let filename = checksum.to_hex(); - let file_path = self.latest_modules_path().join(filename); + let file_path = self.modules_path.join(filename); if file_path.exists() { fs::remove_file(file_path) @@ -161,15 +161,6 @@ impl FileSystemCache { Ok(false) } } - - /// The path to the latest version of the modules. - fn latest_modules_path(&self) -> PathBuf { - let version = format!( - "{}-wasmer{}", - MODULE_SERIALIZATION_VERSION, self.wasmer_module_version - ); - self.base_path.join(version) - } } /// Estimates the in-memory size of a wasmer Module based on the size it takes on disk. @@ -198,6 +189,16 @@ fn target_id(target: &Target) -> String { format!("{}-{:08X}", target.triple(), hash) // print 4 byte hash as 8 hex characters } +/// The path to the latest version of the modules. +fn modules_path(base_path: &Path, wasmer_module_version: u32, target: &Target) -> PathBuf { + let version_dir = format!( + "{}-wasmer{}", + MODULE_SERIALIZATION_VERSION, wasmer_module_version + ); + let target_dir = target_id(target); + base_path.join(version_dir).join(target_dir) +} + #[cfg(test)] mod tests { use std::fs; @@ -270,12 +271,14 @@ mod tests { let module = compile(&wasm, None, &[]).unwrap(); cache.store(&checksum, &module).unwrap(); - let file_path = format!( - "{}/v4-wasmer1/{}", + let mut globber = glob::glob(&format!( + "{}/v4-wasmer1/**/{}", tmp_dir.path().to_string_lossy(), checksum - ); - let _serialized_module = fs::read(file_path).unwrap(); + )) + .expect("Failed to read glob pattern"); + let file_path = globber.next().unwrap().unwrap(); + let _serialized_module = fs::read(&file_path).unwrap(); } #[test] @@ -331,4 +334,22 @@ mod tests { let id2 = target_id(&target); assert_eq!(id1, id2); } + + #[test] + fn modules_path_works() { + let base = PathBuf::from("./modules/"); + let triple = wasmer::Triple { + architecture: wasmer::Architecture::X86_64, + vendor: target_lexicon::Vendor::Nintendo, + operating_system: target_lexicon::OperatingSystem::Fuchsia, + environment: target_lexicon::Environment::Gnu, + binary_format: target_lexicon::BinaryFormat::Coff, + }; + let target = Target::new(triple, wasmer::CpuFeature::POPCNT.into()); + let p = modules_path(&base, 17, &target); + assert_eq!( + p.as_os_str(), + "./modules/v4-wasmer17/x86_64-nintendo-fuchsia-gnu-coff-4721E3F4" + ); + } }