Browse Source

[rust/axum] dependencies and performance (#9785)

* feat: upgraded deps, rust version and edition

* feat: avoid creating SmallRng when only one number is required

* feat: update rust version
Andrew James 4 months ago
parent
commit
f479884794

File diff suppressed because it is too large
+ 282 - 154
frameworks/Rust/axum/Cargo.lock


+ 19 - 19
frameworks/Rust/axum/Cargo.toml

@@ -1,8 +1,8 @@
 [package]
 name = "axum-techempower"
-version = "0.2.1"
+version = "0.3.0"
 authors = ["Dragos Varovici <[email protected]>"]
-edition = "2021"
+edition = "2024"
 
 [[bin]]
 name = "axum"
@@ -39,49 +39,49 @@ simd-json = [
 ]
 
 [dependencies]
-axum = { version = "0.7.9", default-features = false, features = [
+axum = { version = "0.8.3", default-features = false, features = [
     "json",
     "query",
     "http1",
     "tokio",
 ] }
-deadpool = { version = "0.12.1", features = ["rt_tokio_1", "serde", "managed"] }
+deadpool = { version = "0.12.2", features = ["rt_tokio_1", "serde", "managed"] }
 deadpool-postgres = { version = "0.14.1", features = ["rt_tokio_1", "serde"] }
 dotenv = "0.15.0"
 futures = "0.3.31"
 futures-util = "0.3.31"
-mongodb = { version = "3.1.1", features = [
+mongodb = { version = "3.2.3", features = [
     "zstd-compression",
     "snappy-compression",
     "zlib-compression",
 ] }
 num_cpus = "1.16.0"
-rand = { version = "0.8.5", features = ["small_rng"] }
-serde = { version = "1.0.216", features = ["derive"] }
-serde_json = "1.0.134"
-sqlx = { version = "0.8.2", features = [
+rand = { version = "0.9.0", features = ["small_rng"] }
+serde = { version = "1.0.219", features = ["derive"] }
+serde_json = "1.0.140"
+sqlx = { version = "0.8.3", features = [
     "postgres",
     "macros",
     "runtime-tokio",
     "tls-rustls",
 ] }
-tokio = { version = "1.42.0", features = ["full"] }
+tokio = { version = "1.44.2", features = ["full"] }
 tokio-pg-mapper = { version = "0.2.0" }
 tokio-pg-mapper-derive = { version = "0.2.0" }
-tokio-postgres = { version = "0.7.12" }
+tokio-postgres = { version = "0.7.13" }
 tower = { version = "0.5.2", features = ["util"] }
 tower-http = { version = "0.6.2", features = ["set-header"] }
 yarte = "0.15.7"
-simd-json = { version = "0.14.3", optional = true }
-axum-core = { version = "0.4.5", optional = true }
+simd-json = { version = "0.15.0", optional = true }
+axum-core = { version = "0.5.2", optional = true }
 mime = { version = "0.3.17", optional = true }
-bytes = { version = "1.9.0", optional = true }
-serde_path_to_error = { version = "0.1.16", optional = true }
-socket2 = "0.5.8"
-hyper = { version = "1.5", features = ["server", "http1"] }
+bytes = { version = "1.10.1", optional = true }
+serde_path_to_error = { version = "0.1.17", optional = true }
+socket2 = "0.5.9"
+hyper = { version = "1.6", features = ["server", "http1"] }
 hyper-util = { version = "0.1", features = ["tokio", "server-auto", "http1"] }
-quick_cache = "0.6.9"
-mimalloc = "0.1.43"
+quick_cache = "0.6.12"
+mimalloc = "0.1.45"
 
 
 [profile.release]

+ 1 - 2
frameworks/Rust/axum/README.md

@@ -40,5 +40,4 @@ built with Tokio, Tower, and Hyper.
 - Use of PostgreSQL prepared statements cache (where supported).
 - Use of PostgreSQL arrays to execute multi-row database updates with a single `UPDATE` query.
   - This is permitted by the [test requirements](https://github.com/TechEmpower/FrameworkBenchmarks/wiki/Project-Information-Framework-Tests-Overview#database-updates), step (ix).
-- More performance improvements are to be expected in version 0.8:
-  - https://github.com/tokio-rs/axum/issues/1827
+- Use of a fast PRNG

+ 1 - 1
frameworks/Rust/axum/axum.dockerfile

@@ -1,4 +1,4 @@
-FROM docker.io/rust:1.83-slim-bookworm AS builder
+FROM docker.io/rust:1.86-slim-bookworm AS builder
 
 RUN apt-get update && apt-get install -y --no-install-recommends \
     pkg-config libssl-dev \

+ 4 - 4
frameworks/Rust/axum/src/common/mod.rs

@@ -1,7 +1,7 @@
 use std::{env, str::FromStr};
 
 use core::fmt::Debug;
-use rand::{distributions::Uniform, rngs::SmallRng, Rng};
+use rand::{distr::Uniform, rngs::SmallRng, Rng, RngCore};
 pub mod models;
 pub mod utils;
 
@@ -36,14 +36,14 @@ where
 /// Generate a single integer in the range 1 to 10,000 (inclusive)
 #[allow(dead_code)]
 #[inline(always)]
-pub fn random_id(rng: &mut SmallRng) -> i32 {
-    rng.gen_range(1..10_001)
+pub fn random_id(rng: &mut impl RngCore) -> i32 {
+    rng.random_range(1..=10_000)
 }
 
 /// Generate an iterator of integers in the range 1 to 10,000 (inclusive)
 #[allow(dead_code)]
 #[inline(always)]
 pub fn random_ids(rng: &mut SmallRng, count: usize) -> impl Iterator<Item = i32> + use<'_> {
-    rng.sample_iter(Uniform::new(1, 10_001))
+    rng.sample_iter(Uniform::new_inclusive(1, 10_000).unwrap())
         .take(count)
 }

+ 4 - 6
frameworks/Rust/axum/src/main_mongo.rs

@@ -21,7 +21,7 @@ use mongodb::{
     options::{ClientOptions, Compressor},
     Client,
 };
-use rand::{rngs::SmallRng, thread_rng, Rng, SeedableRng};
+use rand::{rngs::SmallRng, rng, SeedableRng};
 use yarte::Template;
 use mimalloc::MiMalloc;
 
@@ -43,9 +43,7 @@ pub struct FortunesTemplate<'a> {
 }
 
 async fn db(DatabaseConnection(db): DatabaseConnection) -> impl IntoResponse {
-    let mut rng = SmallRng::from_rng(&mut thread_rng()).unwrap();
-
-    let random_id = (rng.gen::<u32>() % 10_000 + 1) as i32;
+    let random_id = random_id(&mut rng());
 
     let world = find_world_by_id(db, random_id)
         .await
@@ -60,7 +58,7 @@ async fn queries(
 ) -> impl IntoResponse {
     let q = parse_params(params);
 
-    let mut rng = SmallRng::from_rng(&mut thread_rng()).unwrap();
+    let mut rng = SmallRng::from_rng(&mut rng());
     let worlds = find_worlds(db, &mut rng, q).await;
     let results = worlds.expect("worlds could not be retrieved");
 
@@ -73,7 +71,7 @@ async fn updates(
 ) -> impl IntoResponse {
     let q = parse_params(params);
 
-    let mut rng = SmallRng::from_rng(&mut thread_rng()).unwrap();
+    let mut rng = SmallRng::from_rng(&mut rng());
 
     let worlds = find_worlds(db.clone(), &mut  rng, q)
         .await

+ 4 - 6
frameworks/Rust/axum/src/main_mongo_raw.rs

@@ -32,12 +32,10 @@ use mongodb::{
     options::{ClientOptions, Compressor},
     Client,
 };
-use rand::{rngs::SmallRng, thread_rng, SeedableRng};
+use rand::{rngs::SmallRng, rng, SeedableRng};
 
 async fn db(DatabaseConnection(db): DatabaseConnection) -> impl IntoResponse {
-    let mut rng = SmallRng::from_rng(&mut thread_rng()).unwrap();
-
-    let random_id = random_id(&mut rng);
+    let random_id = random_id(&mut rng());
 
     let world = find_world_by_id(db, random_id)
         .await
@@ -52,7 +50,7 @@ async fn queries(
 ) -> impl IntoResponse {
     let q = parse_params(params);
 
-    let mut rng = SmallRng::from_rng(&mut thread_rng()).unwrap();
+    let mut rng = SmallRng::from_rng(&mut rng());
     let worlds = find_worlds(db, &mut rng, q).await;
     let results = worlds.expect("worlds could not be retrieved");
 
@@ -65,7 +63,7 @@ async fn updates(
 ) -> impl IntoResponse {
     let q = parse_params(params);
 
-    let mut rng = SmallRng::from_rng(&mut thread_rng()).unwrap();
+    let mut rng = SmallRng::from_rng(&mut rng());
 
     let worlds = find_worlds(db.clone(), &mut rng, q)
         .await

+ 3 - 4
frameworks/Rust/axum/src/main_pg.rs

@@ -5,7 +5,7 @@ use axum::{
     extract::Query, http::StatusCode, response::IntoResponse, routing::get, Router,
 };
 use dotenv::dotenv;
-use rand::{rngs::SmallRng, thread_rng, SeedableRng};
+use rand::rng;
 use yarte::Template;
 use mimalloc::MiMalloc;
 
@@ -33,10 +33,9 @@ pub struct FortunesTemplate<'a> {
 }
 
 async fn db(DatabaseConnection(conn): DatabaseConnection) -> impl IntoResponse {
-    let mut rng = SmallRng::from_rng(&mut thread_rng()).unwrap();
-
+    let id = random_id(&mut rng());
     let world = conn
-        .fetch_world_by_id(random_id(&mut rng))
+        .fetch_world_by_id(id)
         .await
         .expect("error loading world");
 

+ 4 - 5
frameworks/Rust/axum/src/main_pg_pool.rs

@@ -13,7 +13,7 @@ use common::simd_json::Json;
 use common::{random_ids, SELECT_ALL_FORTUNES, SELECT_WORLD_BY_ID, UPDATE_WORLDS};
 use dotenv::dotenv;
 use futures_util::{stream::FuturesUnordered, TryStreamExt};
-use rand::{rngs::SmallRng, thread_rng, SeedableRng};
+use rand::{rngs::SmallRng, rng, SeedableRng};
 use yarte::Template;
 use mimalloc::MiMalloc;
 
@@ -38,8 +38,7 @@ pub struct FortunesTemplate<'a> {
 }
 
 async fn db(DatabaseClient(client): DatabaseClient) -> impl IntoResponse {
-    let mut rng = SmallRng::from_rng(&mut thread_rng()).unwrap();
-    let random_id = random_id(&mut rng);
+    let random_id = random_id(&mut rng());
 
     let select = &client.prepare_cached(SELECT_WORLD_BY_ID).await.unwrap();
     let world = fetch_world_by_id(&client, random_id, select)
@@ -55,7 +54,7 @@ async fn queries(
 ) -> impl IntoResponse {
     let q = parse_params(params);
 
-    let mut rng = SmallRng::from_rng(&mut thread_rng()).unwrap();
+    let mut rng = SmallRng::from_rng(&mut rng());
     let select = &client.prepare_cached(SELECT_WORLD_BY_ID).await.unwrap();
     let future_worlds = FuturesUnordered::new();
 
@@ -98,7 +97,7 @@ async fn updates(
 ) -> impl IntoResponse {
     let q = parse_params(params);
 
-    let mut rng = SmallRng::from_entropy();
+    let mut rng = SmallRng::from_rng(&mut rng());
     let select = &client.prepare_cached(SELECT_WORLD_BY_ID).await.unwrap();
     let update = &client.prepare_cached(UPDATE_WORLDS).await.unwrap();
 

+ 5 - 6
frameworks/Rust/axum/src/main_sqlx.rs

@@ -13,7 +13,7 @@ use axum::{
 };
 use dotenv::dotenv;
 use quick_cache::sync::Cache;
-use rand::{rngs::SmallRng, thread_rng, SeedableRng};
+use rand::{rngs::SmallRng, rng, SeedableRng};
 use sqlx::models::World;
 use yarte::Template;
 use mimalloc::MiMalloc;
@@ -42,10 +42,9 @@ pub struct FortunesTemplate<'a> {
 }
 
 async fn db(State(AppState { db, .. }): State<AppState>) -> impl IntoResponse {
-    let mut rng = SmallRng::from_rng(&mut thread_rng()).unwrap();
-
+    let id = random_id(&mut rng());
     let world: World = ::sqlx::query_as(common::SELECT_WORLD_BY_ID)
-        .bind(random_id(&mut rng))
+        .bind(id)
         .fetch_one(&mut *db.acquire().await.unwrap())
         .await
         .expect("error loading world");
@@ -57,7 +56,7 @@ async fn queries(
     State(AppState { db, .. }): State<AppState>,
     Query(params): Query<Params>,
 ) -> impl IntoResponse {
-    let mut rng = SmallRng::from_rng(&mut thread_rng()).unwrap();
+    let mut rng = SmallRng::from_rng(&mut rng());
     let count = parse_params(params);
     let mut worlds: Vec<World> = Vec::with_capacity(count);
 
@@ -100,7 +99,7 @@ async fn cache(
     Query(params): Query<Params>,
 ) -> impl IntoResponse {
     let count = parse_params(params);
-    let mut rng = SmallRng::from_rng(&mut thread_rng()).unwrap();
+    let mut rng = SmallRng::from_rng(&mut rng());
     let mut worlds: Vec<Option<World>> = Vec::with_capacity(count);
     
     for id in random_ids(&mut rng, count) {

+ 1 - 2
frameworks/Rust/axum/src/mongo/database.rs

@@ -1,6 +1,6 @@
 use std::{convert::Infallible, io};
 
-use axum::{async_trait, extract::FromRequestParts, http::request::Parts};
+use axum::{extract::FromRequestParts, http::request::Parts};
 use futures_util::{stream::FuturesUnordered, StreamExt, TryStreamExt};
 use mongodb::{bson::doc, Database};
 use rand::rngs::SmallRng;
@@ -9,7 +9,6 @@ use crate::common::{models::{Fortune, World}, random_ids};
 
 pub struct DatabaseConnection(pub Database);
 
-#[async_trait]
 impl FromRequestParts<Database> for DatabaseConnection {
     type Rejection = Infallible;
 

+ 1 - 2
frameworks/Rust/axum/src/mongo_raw/database.rs

@@ -1,6 +1,6 @@
 use std::{convert::Infallible, io};
 
-use axum::{async_trait, extract::FromRequestParts, http::request::Parts};
+use axum::{extract::FromRequestParts, http::request::Parts};
 use futures_util::{stream::FuturesUnordered, TryStreamExt};
 use mongodb::{
     bson::{doc, RawDocumentBuf},
@@ -12,7 +12,6 @@ use crate::common::{models::World, random_ids};
 
 pub struct DatabaseConnection(pub Database);
 
-#[async_trait]
 impl FromRequestParts<Database> for DatabaseConnection {
     type Rejection = Infallible;
 

+ 4 - 5
frameworks/Rust/axum/src/pg/database.rs

@@ -1,8 +1,8 @@
 use std::{convert::Infallible, io, sync::Arc};
 
-use axum::{async_trait, extract::FromRequestParts, http::request::Parts};
+use axum::{extract::FromRequestParts, http::request::Parts};
 use futures::{stream::futures_unordered::FuturesUnordered, StreamExt, TryStreamExt};
-use rand::{rngs::SmallRng, thread_rng, SeedableRng};
+use rand::{rngs::SmallRng, rng, SeedableRng};
 use tokio::pin;
 use tokio_postgres::{connect, Client, NoTls, Statement};
 
@@ -78,7 +78,7 @@ impl PgConnection {
     }
 
     pub async fn fetch_random_worlds(&self, num: usize) -> Result<Vec<World>, PgError> {
-        let mut rng = SmallRng::from_rng(&mut thread_rng()).unwrap();
+        let mut rng = SmallRng::from_rng(&mut rng());
 
         let futures = FuturesUnordered::new();
 
@@ -93,7 +93,7 @@ impl PgConnection {
         let mut worlds = self.fetch_random_worlds(num).await?;
 
         // Update the worlds with new random numbers
-        let mut rng = SmallRng::from_rng(&mut thread_rng()).unwrap();
+        let mut rng = SmallRng::from_rng(&mut rng());
         let mut ids = Vec::with_capacity(num);
         let mut nids = Vec::with_capacity(num);
 
@@ -139,7 +139,6 @@ impl PgConnection {
 
 pub struct DatabaseConnection(pub Arc<PgConnection>);
 
-#[async_trait]
 impl FromRequestParts<Arc<PgConnection>> for DatabaseConnection {
     type Rejection = Infallible;
 

+ 0 - 2
frameworks/Rust/axum/src/pg_pool/database.rs

@@ -5,7 +5,6 @@ use crate::{
     pg_pool::models::{Fortune, World},
 };
 use axum::{
-    async_trait,
     extract::FromRequestParts,
     http::{request::Parts, StatusCode},
 };
@@ -55,7 +54,6 @@ pub async fn create_pool(
 
 pub struct DatabaseClient(pub Client);
 
-#[async_trait]
 impl FromRequestParts<deadpool_postgres::Pool> for DatabaseClient {
     type Rejection = (StatusCode, String);
 

+ 1 - 1
frameworks/Rust/axum/src/server.rs

@@ -37,7 +37,7 @@ fn set_socket_options(addr: SocketAddr) -> io::Result<tokio::net::TcpListener> {
 }
 
 /// Build an Axum server with consistent configuration, using the high-level API exposed
-/// by Axum 0.7. This is intended for convenience and intentionally does not provide much
+/// by Axum 0.8. This is intended for convenience and intentionally does not provide much
 /// customisability.
 #[allow(dead_code)]
 pub async fn serve(app: Router<()>, port: Option<u16>) {

Some files were not shown because too many files changed in this diff