Skip to content

Commit 794b174

Browse files
committed
Extract versioning and add wasmer module version to folder name
1 parent 1cd7ac9 commit 794b174

File tree

3 files changed

+80
-31
lines changed

3 files changed

+80
-31
lines changed

packages/vm/src/modules/file_system_cache.rs

Lines changed: 22 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ use wasmer::{DeserializeError, Module, Store};
77
use crate::checksum::Checksum;
88
use crate::errors::{VmError, VmResult};
99

10+
use crate::modules::current_wasmer_module_version;
11+
1012
/// Bump this version whenever the module system changes in a way
1113
/// that old stored modules would be corrupt when loaded in the new system.
1214
/// This needs to be done e.g. when switching between the jit/native engine.
@@ -32,16 +34,12 @@ use crate::errors::{VmError, VmResult};
3234
/// Version for Wasmer 2.2.0 which contains a [module breaking change to 2.1.x](https://github.com/wasmerio/wasmer/pull/2747).
3335
const MODULE_SERIALIZATION_VERSION: &str = "v3";
3436

35-
/// This header prefix contains the module type (wasmer-universal),
36-
/// the magic value WASMER\0\0 and a little endian encoded uint32 version number.
37-
/// The full header also contains a length that we do not check.
38-
const EXPECTED_MODULE_HEADER_PREFIX: &[u8] = b"wasmer-universalWASMER\0\0\x01\0\0\0";
39-
4037
/// Representation of a directory that contains compiled Wasm artifacts.
4138
pub struct FileSystemCache {
4239
/// The base path this cache operates in. Within this path, versioned directories are created.
4340
/// A sophisticated version of this cache might be able to read multiple input versions in the future.
4441
base_path: PathBuf,
42+
wasmer_module_version: u32,
4543
}
4644

4745
impl FileSystemCache {
@@ -53,16 +51,17 @@ impl FileSystemCache {
5351
/// This method is unsafe because there's no way to ensure the artifacts
5452
/// stored in this cache haven't been corrupted or tampered with.
5553
pub unsafe fn new(path: impl Into<PathBuf>) -> io::Result<Self> {
56-
if !current_wasmer_module_header().starts_with(EXPECTED_MODULE_HEADER_PREFIX) {
57-
panic!("Wasmer module format changed. Please update the expected version accordingly and bump MODULE_SERIALIZATION_VERSION.");
58-
}
54+
let wasmer_module_version = current_wasmer_module_version();
5955

6056
let path: PathBuf = path.into();
6157
if path.exists() {
6258
let metadata = path.metadata()?;
6359
if metadata.is_dir() {
6460
if !metadata.permissions().readonly() {
65-
Ok(Self { base_path: path })
61+
Ok(Self {
62+
base_path: path,
63+
wasmer_module_version,
64+
})
6665
} else {
6766
// This directory is readonly.
6867
Err(io::Error::new(
@@ -83,7 +82,10 @@ impl FileSystemCache {
8382
} else {
8483
// Create the directory and any parent directories if they don't yet exist.
8584
fs::create_dir_all(&path)?;
86-
Ok(Self { base_path: path })
85+
Ok(Self {
86+
base_path: path,
87+
wasmer_module_version,
88+
})
8789
}
8890
}
8991

@@ -125,23 +127,14 @@ impl FileSystemCache {
125127

126128
/// The path to the latest version of the modules.
127129
fn latest_modules_path(&self) -> PathBuf {
128-
self.base_path.join(MODULE_SERIALIZATION_VERSION)
130+
let version = format!(
131+
"{}-wasmer{}",
132+
MODULE_SERIALIZATION_VERSION, self.wasmer_module_version
133+
);
134+
self.base_path.join(version)
129135
}
130136
}
131137

132-
fn current_wasmer_module_header() -> Vec<u8> {
133-
use crate::wasm_backend::compile;
134-
// echo "(module)" > my.wat && wat2wasm my.wat && hexdump -C my.wasm
135-
const WASM: &[u8] = b"\x00\x61\x73\x6d\x01\x00\x00\x00";
136-
let module = compile(WASM, None, &[]).unwrap();
137-
let mut bytes = module.serialize().unwrap_or_default();
138-
139-
const ENGINE_TYPE_LEN: usize = 16; // https://github.com/wasmerio/wasmer/blob/2.2.0-rc1/lib/engine-universal/src/artifact.rs#L48
140-
const METADATA_HEADER_LEN: usize = 16; // https://github.com/wasmerio/wasmer/blob/2.2.0-rc1/lib/engine/src/artifact.rs#L251-L252
141-
bytes.truncate(ENGINE_TYPE_LEN + METADATA_HEADER_LEN);
142-
bytes
143-
}
144-
145138
#[cfg(test)]
146139
mod tests {
147140
use super::*;
@@ -211,13 +204,11 @@ mod tests {
211204
let module = compile(&wasm, None, &[]).unwrap();
212205
cache.store(&checksum, &module).unwrap();
213206

214-
let file_path = format!("{}/v3/{}", tmp_dir.path().to_string_lossy(), checksum);
207+
let file_path = format!(
208+
"{}/v3-wasmer1/{}",
209+
tmp_dir.path().to_string_lossy(),
210+
checksum
211+
);
215212
let _serialized_module = fs::read(file_path).unwrap();
216213
}
217-
218-
#[test]
219-
fn current_wasmer_module_header_works() {
220-
let header = current_wasmer_module_header();
221-
assert!(header.starts_with(EXPECTED_MODULE_HEADER_PREFIX));
222-
}
223214
}

packages/vm/src/modules/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@ mod file_system_cache;
22
mod in_memory_cache;
33
mod pinned_memory_cache;
44
mod sized_module;
5+
mod versioning;
56

67
pub use file_system_cache::FileSystemCache;
78
pub use in_memory_cache::InMemoryCache;
89
pub use pinned_memory_cache::PinnedMemoryCache;
10+
pub use versioning::current_wasmer_module_version;

packages/vm/src/modules/versioning.rs

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
use std::convert::TryInto;
2+
3+
use crate::wasm_backend::compile;
4+
5+
/// This header prefix contains the module type (wasmer-universal) and
6+
/// the magic value WASMER\0\0.
7+
/// The full header also contains a little endian encoded uint32 version number
8+
/// and a length that we do not check.
9+
const EXPECTED_MODULE_HEADER_PREFIX: &[u8] = b"wasmer-universalWASMER\0\0\x01\0\0\0";
10+
11+
const ENGINE_TYPE_LEN: usize = 16; // https://github.com/wasmerio/wasmer/blob/2.2.0-rc1/lib/engine-universal/src/artifact.rs#L48
12+
const METADATA_HEADER_LEN: usize = 16; // https://github.com/wasmerio/wasmer/blob/2.2.0-rc1/lib/engine/src/artifact.rs#L251-L252
13+
14+
fn current_wasmer_module_header() -> Vec<u8> {
15+
// echo "(module)" > my.wat && wat2wasm my.wat && hexdump -C my.wasm
16+
const WASM: &[u8] = b"\x00\x61\x73\x6d\x01\x00\x00\x00";
17+
let module = compile(WASM, None, &[]).unwrap();
18+
let mut bytes = module.serialize().unwrap_or_default();
19+
20+
bytes.truncate(ENGINE_TYPE_LEN + METADATA_HEADER_LEN);
21+
bytes
22+
}
23+
24+
/// Obtains the module version from Wasmer that is currently used.
25+
/// As long as the overall format does not change, this returns a
26+
/// counter (1 for Wasmer 2.2.0). When the format changes in an
27+
/// unexpected way (e.g. a different engine is used or the meta
28+
/// format changes), this panics. That way we can ensure an
29+
/// incompatible module format can be found early in the development
30+
/// cycle.
31+
pub fn current_wasmer_module_version() -> u32 {
32+
let header = current_wasmer_module_header();
33+
if !header.starts_with(EXPECTED_MODULE_HEADER_PREFIX) {
34+
panic!("Wasmer module format changed. Please update the expected version accordingly and bump MODULE_SERIALIZATION_VERSION.");
35+
}
36+
37+
let metadata = &header[header.len() - METADATA_HEADER_LEN..];
38+
u32::from_le_bytes((&metadata[8..12]).try_into().unwrap())
39+
}
40+
41+
#[cfg(test)]
42+
mod tests {
43+
use super::*;
44+
45+
#[test]
46+
fn current_wasmer_module_header_works() {
47+
let header = current_wasmer_module_header();
48+
assert!(header.starts_with(EXPECTED_MODULE_HEADER_PREFIX));
49+
}
50+
51+
#[test]
52+
fn current_wasmer_module_version_works() {
53+
let version = current_wasmer_module_version();
54+
assert_eq!(version, 1);
55+
}
56+
}

0 commit comments

Comments
 (0)