diff --git a/seaweed-volume/Cargo.toml b/seaweed-volume/Cargo.toml index 01f97e1d7..b3c1fd866 100644 --- a/seaweed-volume/Cargo.toml +++ b/seaweed-volume/Cargo.toml @@ -1,7 +1,10 @@ [package] name = "weed-volume" version = "0.1.0" -edition = "2021" +edition = "2024" +# The edition needs 1.85; the dependency tree needs more. Verified with +# `cargo +1.91.1 check --all-targets` (1.90 fails on the AWS SDK). +rust-version = "1.91.1" description = "SeaweedFS Volume Server — Rust implementation" [lib] diff --git a/seaweed-volume/README.md b/seaweed-volume/README.md index 4367a0722..039cb436b 100644 --- a/seaweed-volume/README.md +++ b/seaweed-volume/README.md @@ -4,7 +4,10 @@ A drop-in replacement for the [SeaweedFS](https://github.com/seaweedfs/seaweedfs ## Building -Requires Rust 1.75+ (2021 edition). +Requires Rust 1.91.1+ (2024 edition), matching `rust-version` in `Cargo.toml`. +The patch release matters: 1.91.0 does not build. The edition itself only needs +1.85; the higher floor comes from the dependency tree — chiefly the AWS SDK — so +it moves with those crates. CI builds on the latest stable. ```bash cd seaweed-volume diff --git a/seaweed-volume/build.rs b/seaweed-volume/build.rs index 99af370a3..90ca9ef26 100644 --- a/seaweed-volume/build.rs +++ b/seaweed-volume/build.rs @@ -3,7 +3,12 @@ fn main() -> Result<(), Box> { // one, so the build needs no package manager and always sees the same // version. An explicit PROTOC still wins, for packagers supplying their own. if std::env::var_os("PROTOC").is_none() { - std::env::set_var("PROTOC", protoc_bin_vendored::protoc_bin_path()?); + // SAFETY: a build script's main runs single-threaded before anything + // else in this process, so no other thread can be reading the + // environment concurrently. + unsafe { + std::env::set_var("PROTOC", protoc_bin_vendored::protoc_bin_path()?); + } } let out_dir = std::path::PathBuf::from(std::env::var("OUT_DIR")?); diff --git a/seaweed-volume/src/config.rs b/seaweed-volume/src/config.rs index 007ad4b0a..5eb5292cf 100644 --- a/seaweed-volume/src/config.rs +++ b/seaweed-volume/src/config.rs @@ -1209,21 +1209,30 @@ mod tests { LOCK.get_or_init(|| Mutex::new(())).lock().unwrap() } + // SAFETY (all env mutation in this module): `set_var`/`remove_var` are + // unsafe as of Rust 2024 because they race with concurrent readers in + // other threads. Every test that reaches these helpers holds + // `process_state_lock()` for the duration, so only one test at a time + // touches the environment and none observes another's edit. fn with_temp_env_var(key: &str, value: Option<&str>, f: F) { let previous = std::env::var_os(key); - match value { - Some(v) => std::env::set_var(key, v), - None => std::env::remove_var(key), + unsafe { + match value { + Some(v) => std::env::set_var(key, v), + None => std::env::remove_var(key), + } } f(); restore_env_var(key, previous); } fn restore_env_var(key: &str, value: Option) { - if let Some(value) = value { - std::env::set_var(key, value); - } else { - std::env::remove_var(key); + unsafe { + if let Some(value) = value { + std::env::set_var(key, value); + } else { + std::env::remove_var(key); + } } } @@ -1268,7 +1277,10 @@ mod tests { .collect(); for key in KEYS { - std::env::remove_var(key); + // SAFETY: as above — the caller holds `process_state_lock()`. + unsafe { + std::env::remove_var(key); + } } f(); @@ -1404,12 +1416,18 @@ mod tests { #[test] fn test_resolve_config_defaults_dir_to_platform_temp_dir() { + // resolve_config reads HOME/USERPROFILE and the WEED_* set, so it has to + // hold the same lock the mutation helpers take — a concurrent set_var + // during this read is exactly what makes those calls unsafe. + let _guard = process_state_lock(); let cfg = resolve_config(Cli::parse_from(["bin"])); assert_eq!(cfg.folders, vec![default_volume_dir()]); } #[test] fn test_resolve_config_index_accepts_redb_and_leveldb_aliases() { + // As above: resolve_config reads the environment. + let _guard = process_state_lock(); let pairs = [ ("memory", NeedleMapKind::InMemory), ("redb", NeedleMapKind::Redb), diff --git a/seaweed-volume/src/server/handlers.rs b/seaweed-volume/src/server/handlers.rs index da7513810..fb40070b1 100644 --- a/seaweed-volume/src/server/handlers.rs +++ b/seaweed-volume/src/server/handlers.rs @@ -2425,7 +2425,7 @@ pub async fn post_handler( } else { None }; - if let (Some(ref expected_md5), Some(ref actual_md5)) = (&content_md5, &original_content_md5) { + if let (Some(expected_md5), Some(actual_md5)) = (&content_md5, &original_content_md5) { if expected_md5 != actual_md5 { return json_error_with_query( StatusCode::BAD_REQUEST, @@ -3382,7 +3382,7 @@ async fn try_expand_chunk_manifest( response_headers.insert(header::ACCEPT_RANGES, "bytes".parse().unwrap()); // Last-Modified — Go sets this on the response writer before tryHandleChunkedFile - if let Some(ref lm) = last_modified_str { + if let Some(lm) = last_modified_str { if let Ok(hval) = lm.parse() { response_headers.insert(header::LAST_MODIFIED, hval); } diff --git a/seaweed-worker/Cargo.toml b/seaweed-worker/Cargo.toml index c3064d660..3255ddb46 100644 --- a/seaweed-worker/Cargo.toml +++ b/seaweed-worker/Cargo.toml @@ -10,7 +10,11 @@ members = ["crates/core", "crates/lance", "crates/sort"] [workspace.package] version = "0.1.0" -edition = "2021" +edition = "2024" +# The edition needs 1.85; the dependency tree needs more. Verified with +# `cargo +1.94.1 check --all-targets` (1.94.0 fails on the AWS SDK that +# lance's `aws` feature pulls in). +rust-version = "1.94.1" [workspace.dependencies] anyhow = "1" diff --git a/seaweed-worker/README.md b/seaweed-worker/README.md index 6dc6eb6cc..f4de6ece3 100644 --- a/seaweed-worker/README.md +++ b/seaweed-worker/README.md @@ -14,6 +14,12 @@ one. ## Building +Requires Rust 1.94.1+ (2024 edition), matching `rust-version` in `Cargo.toml`. +The patch release matters: 1.94.0 does not build. The edition itself only needs +1.85; the higher floor comes from the dependency tree — lance's `aws` feature +pulls in the AWS SDK — so it moves with those crates. CI builds on the latest +stable. + `core` compiles `plugin.proto` with the protoc that protoc-bin-vendored ships, the way seaweed-volume does, so it needs no system install. diff --git a/seaweed-worker/crates/core/Cargo.toml b/seaweed-worker/crates/core/Cargo.toml index e1ae1a10e..2a785124a 100644 --- a/seaweed-worker/crates/core/Cargo.toml +++ b/seaweed-worker/crates/core/Cargo.toml @@ -2,6 +2,7 @@ name = "seaweed-worker-core" version.workspace = true edition.workspace = true +rust-version.workspace = true description = "SeaweedFS plugin.proto worker contract" [lib] diff --git a/seaweed-worker/crates/core/build.rs b/seaweed-worker/crates/core/build.rs index 07a4ab57d..f76f0fdab 100644 --- a/seaweed-worker/crates/core/build.rs +++ b/seaweed-worker/crates/core/build.rs @@ -4,7 +4,12 @@ fn main() -> Result<(), Box> { // version. An explicit PROTOC still wins, for packagers supplying their own // and for the lance crates, whose own build scripts read the same variable. if std::env::var_os("PROTOC").is_none() { - std::env::set_var("PROTOC", protoc_bin_vendored::protoc_bin_path()?); + // SAFETY: a build script's main runs single-threaded before anything + // else in this process, so no other thread can be reading the + // environment concurrently. + unsafe { + std::env::set_var("PROTOC", protoc_bin_vendored::protoc_bin_path()?); + } } // Compiled straight out of the Go tree, the way seaweed-volume already reads diff --git a/seaweed-worker/crates/lance/Cargo.toml b/seaweed-worker/crates/lance/Cargo.toml index 962a2b7ac..c8cf3648a 100644 --- a/seaweed-worker/crates/lance/Cargo.toml +++ b/seaweed-worker/crates/lance/Cargo.toml @@ -2,6 +2,7 @@ name = "weed-lance-worker" version.workspace = true edition.workspace = true +rust-version.workspace = true description = "SeaweedFS maintenance worker for Lance tables" [lib] diff --git a/seaweed-worker/crates/sort/Cargo.toml b/seaweed-worker/crates/sort/Cargo.toml index c24a548c1..4918f42c7 100644 --- a/seaweed-worker/crates/sort/Cargo.toml +++ b/seaweed-worker/crates/sort/Cargo.toml @@ -2,6 +2,7 @@ name = "seaweed-worker-sort" version.workspace = true edition.workspace = true +rust-version.workspace = true description = "The sort specification shared by SeaweedFS sorting jobs" [lib]