release: 3.7.0 — Rust 1.95, tokio 1.52, edition 2024#229
Open
release: 3.7.0 — Rust 1.95, tokio 1.52, edition 2024#229
Conversation
added 13 commits
April 30, 2026 12:36
The bench measures the cost of notify_idle_returned, but the helper
was pub(crate) — and Cargo compiles benches as a separate consumer
crate, so the bench failed to build with E0624 ("private method")
even on the current master. Mark it #[doc(hidden)] pub: still
excluded from the documented public surface of the lib crate, but
reachable from the bench. The helper itself is unchanged.
Foundation for the 3.7.0 upgrade — get the toolchain and async runtime to current stable so the next steps (edition 2024 migration, clippy fixes) don't have to deal with year-old tooling. Rust pinned to 1.95.0 (was 1.87.0); tokio to 1.52.1 (was 1.49.0 in the lockfile). The lockfile picks up matching minor bumps in libc, mio, socket2, and tokio-macros that the new tokio requires.
Step 2 of the 3.7.0 upgrade. Bumps the project to Rust edition 2024 and adapts source to the new language defaults. Two production paths required real code changes: - std::env::remove_var becomes unsafe in 2024 (it can race with other threads reading the environment); both call sites in run_server are now wrapped in unsafe blocks. - unsafe fn bodies are no longer implicit unsafe blocks; each unsafe fn in the daemon module now opens an explicit unsafe block over its body. The remaining source edits are pattern-binding cleanups that 2024's match ergonomics make redundant (if let Some(ref x) collapses to if let Some(x)). The bulk of the diff is rustfmt under edition 2024 — formatter defaults shifted (import grouping, trailing-comment alignment). Note: cargo clippy --deny warnings does not pass yet on this commit. Edition 2024 enables collapsible_if-style diagnostics on the new if-let-chains, and rustc 1.95 surfaces several manual_checked_ops, collapsible_match, and similar lints — all addressed in the next commit (C3).
Step 3 of the 3.7.0 upgrade. cargo clippy --fix handled the bulk
auto-rewritably (collapsible_if into 2024 if-let-chains, plus
collapsible_match, derivable_impls, useless_conversion, and
unnecessary_unwrap across admin, app, auth, pool, client, server,
util, and several test helpers).
Eleven lints required manual rewrites:
- if-x-is-some-then-x-unwrap → if-let-Some patterns in scram and
server_backend.
- result.is_err && unwrap_err → let-Err binding in entrypoint and
migration (uses 2024 let-chains).
- sort_by(reverse-cmp) → sort_by_key(Reverse) in log_level, pool
inner, and a bench helper.
- Manual `if x > 0 { y / x } else { default }` → checked_div(x)
.unwrap_or(default) in pool inner, stats address, and stats pool.
Same observable behavior; the default already matched the
original else-branch in each place.
cargo fmt and cargo clippy --all-targets --deny warnings now
both exit clean on the branch.
Wraps up the 3.7.0 toolchain refresh: bumps the project version and adds the changelog entry covering the four preceding commits. No user-visible behavior changes since 3.6.4 — this release packages the rust/tokio/edition upgrade landed in the preceding commits. Operators upgrading from 3.6.x do not need any config or deployment changes.
Why: the test-runner docker image was pinned to rustc 1.87.0, which made make test-bdd (and the corresponding CI job) fail at the MSRV check after Cargo.toml moved to rust-version 1.95.0 in the preceding commits. The image tag in bdd-tests.yml is derived from a hash of tests/nix/flake.nix + flake.lock, so changing the pin triggers a fresh image build on the next workflow run; subsequent BDD jobs pick up the new rustc automatically.
The previous test-runner image bump pinned rust-bin.stable.\"1.95.0\" in flake.nix, but the existing flake.lock snapshot of rust-overlay (2025-12-27) didn't have that attribute yet, so nix build failed in CI with: error: attribute '\"1.95.0\"' missing. Refresh nixpkgs, flake-parts, and rust-overlay locks so the new toolchain is available in the next CI image build.
The 3.7.0 toolchain bump pinned rust-toolchain.toml and Cargo.toml
to 1.95.0, but several other places still hard-coded 1.87.0 and
broke their CI jobs:
- copr-publish, launchpad-publish — RUST_VERSION env.
- build-packages — wget URL for rust-1.87.0 in the debian and rpm
matrix, plus the rust:1.87.0-alpine container for the static
musl build.
- pkg/rpm/pg-doorman.spec — %global rust_version.
- Dockerfile — base image rust:1.87.0-slim-bookworm.
- benches/setup-and-run-bench.sh — rustup --default-toolchain.
- documentation/{en,ru}/src/tutorials/contributing.md — the
"Rust 1.87.0" line under the prerequisites list.
Also fixes the nix test-runner image against the 2026-04-28
nixpkgs snapshot, which removed two attributes used by the
flake:
- nodePackages was deprecated; npm now ships bundled with
nodejs_22, so the standalone nodePackages.npm entry is dropped.
- go_1_24 was dropped; switch to go_1_25 (still satisfies
tests/go/go.mod's go 1.24.0 minimum).
Now that MSRV is 1.95.0, replace a few verbose stdlib idioms with their newer equivalents where it improves readability: - Duration::from_secs(60) → Duration::from_mins(1) for the JWT TTL in server authentication (was from_secs(120) → from_mins(2)) and the default server idle-check timeout — minutes are the natural unit for these knobs. - Manual is_char_boundary backwards walk in patroni::client:: truncate_str collapses to str::floor_char_boundary, dropping the explicit loop. - Three patroni_proxy port-test backend mocks switched to from_mins(1) for the keep-open sleep, consistent with the config-default change. Other Duration::from_secs sites kept as-is on purpose: their surrounding comments compare values in seconds (e.g. "60s vs loop_wait of 10s"), and converting to minutes would split the comment from the code unit.
Edition 2024 requires extern blocks to be marked unsafe. The
TLS migration FFI block in client::migration was guarded by the
tls-migration feature, so the cargo check during the edition 2024
migration commit (without the feature) didn't surface it; CI's
TLS Migration BDD job rebuilds with the feature on and failed
with: error: extern blocks must be unsafe.
Mark the block as unsafe extern "C". The function bodies inside
were already wrapped in their own unsafe { ... } blocks at the
call sites, so no other change is needed.
Five production sites called unwrap on values that depend on external input or earlier guards. Each becomes a typed error or a let-Some pattern, so a malformed PG packet or a config mismatch surfaces as a regular Error instead of a panic. - ParameterStatus parsing in server::protocol_io and server::server_backend now propagates the parse error from read_string with ? — the function signature for handle_parameter_status grew a Result so the caller can act on it; a malformed packet from the backend cleanly tears down that connection instead of aborting the worker. - Static-MD5 verification in auth::mod (passthrough_md5_verify) binds the stripped hash via let-Some on the MD5_PASSWORD_PREFIX prefix — the previous unwrap relied on the caller having already done starts_with, which made the call site fragile to refactors. - The auth_query MD5 path is rewritten as let-Some chains so the prefix strip can never panic, even if the cache returns an unexpected entry. - server::authentication's clear-password branch collapses the is_none guard plus two unwrap+clone pairs into a single let-Some pattern, and the JWT key strip is also let-Some'd — no behavior change beyond the panic being a typed error.
Five message builders allocated a String only to copy its bytes
into a BytesMut/Vec and discard it. Each now writes directly to
the destination buffer:
- md5_hash_second_pass: write! into a presized Vec<u8> instead of
format!(...).chars().map(as u8).collect — also drops the UTF-8
decode/re-encode round-trip on what is already ASCII-only hex.
- error_message and wrong_password: put_slice the literal/borrowed
bytes plus a put_u8(0) for the NUL, instead of format!("{x}\\0")
→ as_bytes.
- row_description: same pattern for the per-column name field.
These run on every error reply, every md5 auth handshake, and
once per row in administrative SELECTs. Behavior is byte-for-byte
identical (verified by visual diff of the bytes pushed).
Public message helpers row_description and data_row_nullable used
to take &Vec<T>; the slice form &[T] is the idiomatic Rust API for
read-only access and lets callers pass array literals directly,
without an intermediate Vec allocation.
All call sites in the admin module simplified accordingly:
&vec![("name", DataType::Text)] → &[("name", DataType::Text)],
which clippy::useless_vec now also enforces.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
coordinator_benchmarksfailed to compile on master becausenotify_idle_returnedwaspub(crate)and benches/* sees pg_doorman as an external crate. Now#[doc(hidden)] pub.Commits
The five commits are intentionally kept separate so bisect can isolate the source of any regression:
fix(bench): exposenotify_idle_returnedforcoordinator_benchmarkschore(deps): bump Rust toolchain + tokiochore: migrate to edition 2024chore(clippy): fix lints surfaced by 1.95 + 2024release: 3.7.0 (version + changelog)Local verification
cargo fmt— cleancargo clippy --all-targets -- --deny warnings— cleancargo build --release— OK (~1m13s)cargo test --test bdd— 35/36 pass; the single failure isgo: go.mod requires go >= 1.24.0 (running go 1.23.7), which is pre-existing on master and unrelated to this PRmake test-bdd— blocked locally because theghcr.io/ozontech/pg_doorman/test-runnerdocker image still ships rustc 1.87. Needs an image rebuild against rustc 1.95 so contributors can run the suite locally.Notes
patches/(rust-native-tls, tokio-native-tls, openssl-src) compiled cleanly against the new tokio with no changes; no resync was needed.test-runnerimage somake test-bddworks for contributors.