Browse Source

[xitca-web] disable broken test (#10419)

* [xitca-web] disable broken test

* fxi toasty build

* fix lifetime of pool connetion in update

* improve perf of toasty
fakeshadow 2 days ago
parent
commit
7d18607b6a

+ 38 - 16
frameworks/Rust/xitca-web/Cargo.lock

@@ -122,9 +122,9 @@ dependencies = [
 
 
 [[package]]
 [[package]]
 name = "bumpalo"
 name = "bumpalo"
-version = "3.19.0"
+version = "3.19.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43"
+checksum = "5dd9dc738b7a8311c7ade152424974d8115f2cdad61e8dab8dac9f2362298510"
 
 
 [[package]]
 [[package]]
 name = "by_address"
 name = "by_address"
@@ -225,6 +225,27 @@ dependencies = [
  "syn",
  "syn",
 ]
 ]
 
 
+[[package]]
+name = "deadpool"
+version = "0.12.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0be2b1d1d6ec8d846f05e137292d0b89133caf95ef33695424c09568bdd39b1b"
+dependencies = [
+ "deadpool-runtime",
+ "lazy_static",
+ "num_cpus",
+ "tokio",
+]
+
+[[package]]
+name = "deadpool-runtime"
+version = "0.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "092966b41edc516079bdf31ec78a2e0588d1d0c08f78b91d8307215928642b2b"
+dependencies = [
+ "tokio",
+]
+
 [[package]]
 [[package]]
 name = "diesel"
 name = "diesel"
 version = "2.3.4"
 version = "2.3.4"
@@ -1277,7 +1298,7 @@ checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596"
 [[package]]
 [[package]]
 name = "std-util"
 name = "std-util"
 version = "0.1.0"
 version = "0.1.0"
-source = "git+https://github.com/fakeshadow/toasty?branch=engine#b4a6ff95cb23f34c06c383806a0d00f782b6acbc"
+source = "git+https://github.com/fakeshadow/toasty?branch=engine#4e95852bfc90b027a0bdfde8a413263f76581a9e"
 dependencies = [
 dependencies = [
  "heck",
  "heck",
  "pluralizer",
  "pluralizer",
@@ -1377,11 +1398,12 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
 [[package]]
 [[package]]
 name = "toasty"
 name = "toasty"
 version = "0.1.0"
 version = "0.1.0"
-source = "git+https://github.com/fakeshadow/toasty?branch=engine#b4a6ff95cb23f34c06c383806a0d00f782b6acbc"
+source = "git+https://github.com/fakeshadow/toasty?branch=engine#4e95852bfc90b027a0bdfde8a413263f76581a9e"
 dependencies = [
 dependencies = [
  "anyhow",
  "anyhow",
  "async-stream",
  "async-stream",
  "by_address",
  "by_address",
+ "deadpool",
  "index_vec",
  "index_vec",
  "indexmap",
  "indexmap",
  "toasty-core",
  "toasty-core",
@@ -1395,7 +1417,7 @@ dependencies = [
 [[package]]
 [[package]]
 name = "toasty-codegen"
 name = "toasty-codegen"
 version = "0.1.0"
 version = "0.1.0"
-source = "git+https://github.com/fakeshadow/toasty?branch=engine#b4a6ff95cb23f34c06c383806a0d00f782b6acbc"
+source = "git+https://github.com/fakeshadow/toasty?branch=engine#4e95852bfc90b027a0bdfde8a413263f76581a9e"
 dependencies = [
 dependencies = [
  "proc-macro2",
  "proc-macro2",
  "quote",
  "quote",
@@ -1406,7 +1428,7 @@ dependencies = [
 [[package]]
 [[package]]
 name = "toasty-core"
 name = "toasty-core"
 version = "0.1.0"
 version = "0.1.0"
-source = "git+https://github.com/fakeshadow/toasty?branch=engine#b4a6ff95cb23f34c06c383806a0d00f782b6acbc"
+source = "git+https://github.com/fakeshadow/toasty?branch=engine#4e95852bfc90b027a0bdfde8a413263f76581a9e"
 dependencies = [
 dependencies = [
  "anyhow",
  "anyhow",
  "async-trait",
  "async-trait",
@@ -1420,7 +1442,7 @@ dependencies = [
 [[package]]
 [[package]]
 name = "toasty-macros"
 name = "toasty-macros"
 version = "0.1.0"
 version = "0.1.0"
-source = "git+https://github.com/fakeshadow/toasty?branch=engine#b4a6ff95cb23f34c06c383806a0d00f782b6acbc"
+source = "git+https://github.com/fakeshadow/toasty?branch=engine#4e95852bfc90b027a0bdfde8a413263f76581a9e"
 dependencies = [
 dependencies = [
  "proc-macro2",
  "proc-macro2",
  "quote",
  "quote",
@@ -1432,7 +1454,7 @@ dependencies = [
 [[package]]
 [[package]]
 name = "toasty-sql"
 name = "toasty-sql"
 version = "0.1.0"
 version = "0.1.0"
-source = "git+https://github.com/fakeshadow/toasty?branch=engine#b4a6ff95cb23f34c06c383806a0d00f782b6acbc"
+source = "git+https://github.com/fakeshadow/toasty?branch=engine#4e95852bfc90b027a0bdfde8a413263f76581a9e"
 dependencies = [
 dependencies = [
  "anyhow",
  "anyhow",
  "toasty-core",
  "toasty-core",
@@ -1767,7 +1789,7 @@ checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9"
 [[package]]
 [[package]]
 name = "xitca-codegen"
 name = "xitca-codegen"
 version = "0.4.0"
 version = "0.4.0"
-source = "git+http://github.com/HFQR/xitca-web?rev=b723c0c#b723c0c5800d82beca768bbfff273b3e6d1abf52"
+source = "git+http://github.com/HFQR/xitca-web?rev=faf1ae2#faf1ae24bf966a1dddccf02f923ecac28b387c03"
 dependencies = [
 dependencies = [
  "quote",
  "quote",
  "syn",
  "syn",
@@ -1776,7 +1798,7 @@ dependencies = [
 [[package]]
 [[package]]
 name = "xitca-http"
 name = "xitca-http"
 version = "0.7.1"
 version = "0.7.1"
-source = "git+http://github.com/HFQR/xitca-web?rev=b723c0c#b723c0c5800d82beca768bbfff273b3e6d1abf52"
+source = "git+http://github.com/HFQR/xitca-web?rev=faf1ae2#faf1ae24bf966a1dddccf02f923ecac28b387c03"
 dependencies = [
 dependencies = [
  "futures-core",
  "futures-core",
  "http",
  "http",
@@ -1809,7 +1831,7 @@ dependencies = [
 [[package]]
 [[package]]
 name = "xitca-postgres"
 name = "xitca-postgres"
 version = "0.3.0"
 version = "0.3.0"
-source = "git+http://github.com/HFQR/xitca-web?rev=b723c0c#b723c0c5800d82beca768bbfff273b3e6d1abf52"
+source = "git+http://github.com/HFQR/xitca-web?rev=faf1ae2#faf1ae24bf966a1dddccf02f923ecac28b387c03"
 dependencies = [
 dependencies = [
  "fallible-iterator",
  "fallible-iterator",
  "futures-core",
  "futures-core",
@@ -1825,7 +1847,7 @@ dependencies = [
 [[package]]
 [[package]]
 name = "xitca-postgres-diesel"
 name = "xitca-postgres-diesel"
 version = "0.2.0"
 version = "0.2.0"
-source = "git+https://github.com/fakeshadow/xitca-postgres-diesel?rev=fb5dcba#fb5dcba5a89164a880a3e82d62dcb3ae5e99ae6e"
+source = "git+https://github.com/fakeshadow/xitca-postgres-diesel?rev=1bd39ac#1bd39ac23f8bb2f45d44b94c775a547ee92db494"
 dependencies = [
 dependencies = [
  "diesel",
  "diesel",
  "diesel-async",
  "diesel-async",
@@ -1838,7 +1860,7 @@ dependencies = [
 [[package]]
 [[package]]
 name = "xitca-postgres-toasty"
 name = "xitca-postgres-toasty"
 version = "0.1.0"
 version = "0.1.0"
-source = "git+https://github.com/fakeshadow/xitca-postgres-toasty?rev=02c6604#02c6604beaf9f9792eb2c4e54d23cbddc34675fc"
+source = "git+https://github.com/fakeshadow/xitca-postgres-toasty?rev=270fe35#270fe35a3b9ac8b5cb3560e14c5a00e52d04eeeb"
 dependencies = [
 dependencies = [
  "anyhow",
  "anyhow",
  "futures-core",
  "futures-core",
@@ -1863,7 +1885,7 @@ dependencies = [
 [[package]]
 [[package]]
 name = "xitca-server"
 name = "xitca-server"
 version = "0.5.0"
 version = "0.5.0"
-source = "git+http://github.com/HFQR/xitca-web?rev=b723c0c#b723c0c5800d82beca768bbfff273b3e6d1abf52"
+source = "git+http://github.com/HFQR/xitca-web?rev=faf1ae2#faf1ae24bf966a1dddccf02f923ecac28b387c03"
 dependencies = [
 dependencies = [
  "socket2",
  "socket2",
  "tokio",
  "tokio",
@@ -1877,7 +1899,7 @@ dependencies = [
 [[package]]
 [[package]]
 name = "xitca-service"
 name = "xitca-service"
 version = "0.3.0"
 version = "0.3.0"
-source = "git+http://github.com/HFQR/xitca-web?rev=b723c0c#b723c0c5800d82beca768bbfff273b3e6d1abf52"
+source = "git+http://github.com/HFQR/xitca-web?rev=faf1ae2#faf1ae24bf966a1dddccf02f923ecac28b387c03"
 
 
 [[package]]
 [[package]]
 name = "xitca-unsafe-collection"
 name = "xitca-unsafe-collection"
@@ -1922,7 +1944,7 @@ dependencies = [
 [[package]]
 [[package]]
 name = "xitca-web"
 name = "xitca-web"
 version = "0.7.1"
 version = "0.7.1"
-source = "git+http://github.com/HFQR/xitca-web?rev=b723c0c#b723c0c5800d82beca768bbfff273b3e6d1abf52"
+source = "git+http://github.com/HFQR/xitca-web?rev=faf1ae2#faf1ae24bf966a1dddccf02f923ecac28b387c03"
 dependencies = [
 dependencies = [
  "futures-core",
  "futures-core",
  "pin-project-lite",
  "pin-project-lite",

+ 11 - 13
frameworks/Rust/xitca-web/Cargo.toml

@@ -6,7 +6,7 @@ edition = "2024"
 [[bin]]
 [[bin]]
 name = "xitca-web"
 name = "xitca-web"
 path = "./src/main.rs"
 path = "./src/main.rs"
-required-features = ["io-uring", "json", "pg", "router", "template"]
+required-features = ["io-uring", "pg", "router", "template"]
 
 
 [[bin]]
 [[bin]]
 name = "xitca-web-barebone"
 name = "xitca-web-barebone"
@@ -32,8 +32,6 @@ diesel = ["dep:diesel", "dep:diesel-async", "dep:xitca-postgres-diesel", "dep:fu
 toasty = ["dep:toasty", "dep:xitca-postgres-toasty", "futures-util/alloc"]
 toasty = ["dep:toasty", "dep:xitca-postgres-toasty", "futures-util/alloc"]
 # http router optional
 # http router optional
 router = ["xitca-http/router"]
 router = ["xitca-http/router"]
-# web optional
-web = ["dep:xitca-web"]
 # web with macros optional
 # web with macros optional
 web-codegen = ["xitca-web/codegen", "xitca-web/urlencoded"]
 web-codegen = ["xitca-web/codegen", "xitca-web/urlencoded"]
 # template optional
 # template optional
@@ -41,7 +39,8 @@ template = ["dep:sailfish"]
 # io-uring optional
 # io-uring optional
 io-uring = ["dep:tokio-uring", "xitca-http/io-uring", "xitca-server/io-uring"]
 io-uring = ["dep:tokio-uring", "xitca-http/io-uring", "xitca-server/io-uring"]
 # unrealistic performance optimization
 # unrealistic performance optimization
-perf = ["dep:core_affinity", "dep:mimalloc", "tokio/parking_lot"]
+perf = ["perf-allocator", "dep:core_affinity", "tokio/parking_lot"]
+perf-allocator = ["dep:mimalloc"]
 # regular json serializer
 # regular json serializer
 json = ["serde_json"]
 json = ["serde_json"]
 # performance optimization json serializer
 # performance optimization json serializer
@@ -99,10 +98,9 @@ codegen-units = 1
 panic = "abort"
 panic = "abort"
 
 
 [patch.crates-io]
 [patch.crates-io]
-xitca-postgres-diesel = { git = "https://github.com/fakeshadow/xitca-postgres-diesel", rev = "fb5dcba" }
-xitca-postgres-toasty = { git = "https://github.com/fakeshadow/xitca-postgres-toasty", rev = "02c6604" }
+xitca-postgres-diesel = { git = "https://github.com/fakeshadow/xitca-postgres-diesel", rev = "1bd39ac" }
+xitca-postgres-toasty = { git = "https://github.com/fakeshadow/xitca-postgres-toasty", rev = "270fe35" }
 
 
-# personal fork for efficient toasty engine fine tuned with pipelined xitca-postgres client
 toasty = { git = "https://github.com/fakeshadow/toasty", branch = "engine" }
 toasty = { git = "https://github.com/fakeshadow/toasty", branch = "engine" }
 toasty-core = { git = "https://github.com/fakeshadow/toasty", branch = "engine" }
 toasty-core = { git = "https://github.com/fakeshadow/toasty", branch = "engine" }
 toasty-sql = { git = "https://github.com/fakeshadow/toasty", branch = "engine" }
 toasty-sql = { git = "https://github.com/fakeshadow/toasty", branch = "engine" }
@@ -110,9 +108,9 @@ toasty-sql = { git = "https://github.com/fakeshadow/toasty", branch = "engine" }
 # personal fork of tokio-uring with tokio local runtime enabled
 # personal fork of tokio-uring with tokio local runtime enabled
 tokio-uring = { git = "http://github.com/fakeshadow/tokio-uring", rev = "c3d5887" }
 tokio-uring = { git = "http://github.com/fakeshadow/tokio-uring", rev = "c3d5887" }
 
 
-xitca-codegen = { git = "http://github.com/HFQR/xitca-web", rev = "b723c0c" }
-xitca-http = { git = "http://github.com/HFQR/xitca-web", rev = "b723c0c" }
-xitca-postgres = { git = "http://github.com/HFQR/xitca-web", rev = "b723c0c" }
-xitca-server = { git = "http://github.com/HFQR/xitca-web", rev = "b723c0c" }
-xitca-service = { git = "http://github.com/HFQR/xitca-web", rev = "b723c0c" }
-xitca-web = { git = "http://github.com/HFQR/xitca-web", rev = "b723c0c" }
+xitca-codegen = { git = "http://github.com/HFQR/xitca-web", rev = "faf1ae2" }
+xitca-http = { git = "http://github.com/HFQR/xitca-web", rev = "faf1ae2" }
+xitca-postgres = { git = "http://github.com/HFQR/xitca-web", rev = "faf1ae2" }
+xitca-server = { git = "http://github.com/HFQR/xitca-web", rev = "faf1ae2" }
+xitca-service = { git = "http://github.com/HFQR/xitca-web", rev = "faf1ae2" }
+xitca-web = { git = "http://github.com/HFQR/xitca-web", rev = "faf1ae2" }

+ 0 - 1
frameworks/Rust/xitca-web/benchmark_config.json

@@ -50,7 +50,6 @@
         "db_url": "/db",
         "db_url": "/db",
         "fortune_url": "/fortunes",
         "fortune_url": "/fortunes",
         "query_url": "/queries?q=",
         "query_url": "/queries?q=",
-        "update_url": "/updates?q=",
         "port": 8080,
         "port": 8080,
         "approach": "realistic",
         "approach": "realistic",
         "classification": "fullstack",
         "classification": "fullstack",

+ 94 - 86
frameworks/Rust/xitca-web/src/db.rs

@@ -1,5 +1,3 @@
-use core::cell::RefCell;
-
 use xitca_postgres::{
 use xitca_postgres::{
     Execute,
     Execute,
     dev::Query,
     dev::Query,
@@ -13,107 +11,117 @@ use crate::{
     util::{Error, HandleResult, Rand},
     util::{Error, HandleResult, Rand},
 };
 };
 
 
-pub const FORTUNE_STMT: StatementNamed = Statement::named("SELECT id,message FROM fortune", &[]);
-
-pub const WORLD_STMT: StatementNamed = Statement::named("SELECT id,randomnumber FROM world WHERE id=$1", &[Type::INT4]);
-
-pub const UPDATE_STMT: StatementNamed = Statement::named(
-    "UPDATE world SET randomnumber=w.r FROM (SELECT unnest($1) as i,unnest($2) as r) w WHERE world.id=w.i",
-    &[Type::INT4_ARRAY, Type::INT4_ARRAY],
-);
-
 #[cold]
 #[cold]
 #[inline(never)]
 #[inline(never)]
 fn not_found() -> Error {
 fn not_found() -> Error {
     "request World does not exist".into()
     "request World does not exist".into()
 }
 }
 
 
-pub(crate) async fn db<C>(conn: C, rng: &RefCell<Rand>, stmt: &Statement) -> HandleResult<World>
-where
-    C: Query,
-{
-    let id = rng.borrow_mut().gen_id();
-    let mut res = stmt.bind([id]).query(&conn).await?;
-    drop(conn);
-    let row = res.try_next().await?.ok_or_else(not_found)?;
-    Ok(World::new(row.get(0), row.get(1)))
+#[derive(Default)]
+pub struct Exec {
+    rng: core::cell::RefCell<Rand>,
 }
 }
 
 
-pub(crate) async fn queries<C>(conn: C, rng: &RefCell<Rand>, stmt: &Statement, num: u16) -> HandleResult<Vec<World>>
-where
-    C: Query,
-{
-    let get = rng
-        .borrow_mut()
-        .gen_multi()
-        .take(num as _)
-        .map(|id| stmt.bind([id]).query(&conn))
-        .collect::<Vec<_>>();
-
-    drop(conn);
-
-    let mut worlds = Vec::with_capacity(num as _);
-
-    for get in get {
-        let mut res = get.await?;
+impl Exec {
+    pub const FORTUNE_STMT: StatementNamed<'_> = Statement::named("SELECT id,message FROM fortune", &[]);
+    pub const WORLD_STMT: StatementNamed<'_> =
+        Statement::named("SELECT id,randomnumber FROM world WHERE id=$1", &[Type::INT4]);
+    pub const UPDATE_STMT: StatementNamed<'_> = Statement::named(
+        "UPDATE world SET randomnumber=w.r FROM (SELECT unnest($1) as i,unnest($2) as r) w WHERE world.id=w.i",
+        &[Type::INT4_ARRAY, Type::INT4_ARRAY],
+    );
+
+    pub(crate) async fn db<C>(&self, conn: C, stmt: &Statement) -> HandleResult<World>
+    where
+        C: Query,
+    {
+        let id = self.rng.borrow_mut().gen_id();
+        let mut res = stmt.bind([id]).query(&conn).await?;
+        drop(conn);
         let row = res.try_next().await?.ok_or_else(not_found)?;
         let row = res.try_next().await?.ok_or_else(not_found)?;
-        worlds.push(World::new(row.get(0), row.get(1)));
+        Ok(World::new(row.get(0), row.get(1)))
     }
     }
 
 
-    Ok(worlds)
-}
-
-pub(crate) async fn updates<C>(
-    conn: C,
-    rng: &RefCell<Rand>,
-    world_stmt: &Statement,
-    update_stmt: &Statement,
-    num: u16,
-) -> HandleResult<Vec<World>>
-where
-    C: Query,
-{
-    let mut rng = rng.borrow_mut();
-    let mut ids = rng.gen_multi().take(num as _).collect::<Vec<_>>();
-    ids.sort();
-
-    let (get, rngs, worlds) = ids
-        .iter()
-        .cloned()
-        .zip(rng.gen_multi())
-        .map(|(id, rand)| {
-            let get = world_stmt.bind([id]).query(&conn);
-            (get, rand, World::new(id, rand))
-        })
-        .collect::<(Vec<_>, Vec<_>, Vec<_>)>();
-
-    let update = update_stmt.bind([&ids, &rngs]).query(&conn);
-
-    drop(conn);
-    drop(rng);
-
-    for get in get {
-        let _rand = get.await?.try_next().await?.ok_or_else(not_found)?.get::<i32>(1);
+    pub(crate) async fn queries<C>(&self, conn: C, stmt: &Statement, num: u16) -> HandleResult<Vec<World>>
+    where
+        C: Query,
+    {
+        let get = self
+            .rng
+            .borrow_mut()
+            .gen_multi()
+            .take(num as _)
+            .map(|id| stmt.bind([id]).query(&conn))
+            .collect::<Vec<_>>();
+
+        drop(conn);
+
+        let mut worlds = Vec::with_capacity(num as _);
+
+        for get in get {
+            let mut res = get.await?;
+            let row = res.try_next().await?.ok_or_else(not_found)?;
+            worlds.push(World::new(row.get(0), row.get(1)));
+        }
+
+        Ok(worlds)
     }
     }
 
 
-    update.await?;
+    pub(crate) async fn updates<C>(
+        &self,
+        conn: C,
+        world_stmt: &Statement,
+        update_stmt: &Statement,
+        num: u16,
+    ) -> HandleResult<Vec<World>>
+    where
+        C: Query,
+    {
+        let (worlds, get, update) = {
+            let mut rng = self.rng.borrow_mut();
+            let mut ids = rng.gen_multi().take(num as _).collect::<Vec<_>>();
+            ids.sort();
+
+            let (get, rngs, worlds) = ids
+                .iter()
+                .cloned()
+                .zip(rng.gen_multi())
+                .map(|(id, rand)| {
+                    let get = world_stmt.bind([id]).query(&conn);
+                    (get, rand, World::new(id, rand))
+                })
+                .collect::<(Vec<_>, Vec<_>, Vec<_>)>();
+
+            let update = update_stmt.bind([&ids, &rngs]).query(&conn);
+
+            drop(conn);
+
+            (worlds, get, update)
+        };
+
+        for get in get {
+            let _rand = get.await?.try_next().await?.ok_or_else(not_found)?.get::<i32>(1);
+        }
+
+        update.await?;
+
+        Ok(worlds)
+    }
 
 
-    Ok(worlds)
-}
+    pub(crate) async fn fortunes<C>(conn: C, stmt: &Statement) -> HandleResult<Fortunes>
+    where
+        C: Query,
+    {
+        let mut res = stmt.query(&conn).await?;
 
 
-pub(crate) async fn fortunes<C>(conn: C, stmt: &Statement) -> HandleResult<Fortunes>
-where
-    C: Query,
-{
-    let mut res = stmt.query(&conn).await?;
+        drop(conn);
 
 
-    drop(conn);
+        let mut fortunes = Vec::with_capacity(16);
 
 
-    let mut fortunes = Vec::with_capacity(16);
+        while let Some(row) = res.try_next().await? {
+            fortunes.push(Fortune::new(row.get(0), row.get::<String>(1)));
+        }
 
 
-    while let Some(row) = res.try_next().await? {
-        fortunes.push(Fortune::new(row.get(0), row.get::<String>(1)));
+        Ok(Fortunes::new(fortunes))
     }
     }
-
-    Ok(Fortunes::new(fortunes))
 }
 }

+ 19 - 20
frameworks/Rust/xitca-web/src/db_pool.rs

@@ -1,47 +1,46 @@
 use xitca_postgres::{Execute, pool::Pool};
 use xitca_postgres::{Execute, pool::Pool};
 
 
 use super::{
 use super::{
+    db::Exec,
     ser::{Fortunes, World},
     ser::{Fortunes, World},
-    util::{DB_URL, HandleResult, Rand},
+    util::{DB_URL, HandleResult},
 };
 };
 
 
-use crate::db::{self, FORTUNE_STMT, UPDATE_STMT, WORLD_STMT};
-
 pub struct Client {
 pub struct Client {
     pool: Pool,
     pool: Pool,
-    rng: core::cell::RefCell<Rand>,
-}
-
-pub async fn create() -> HandleResult<Client> {
-    Ok(Client {
-        pool: Pool::builder(DB_URL).capacity(1).build()?,
-        rng: Default::default(),
-    })
+    exec: Exec,
 }
 }
 
 
 impl Client {
 impl Client {
+    pub async fn create() -> HandleResult<Self> {
+        Ok(Self {
+            pool: Pool::builder(DB_URL).capacity(1).build()?,
+            exec: Default::default(),
+        })
+    }
+
     pub async fn db(&self) -> HandleResult<World> {
     pub async fn db(&self) -> HandleResult<World> {
         let mut conn = self.pool.get().await?;
         let mut conn = self.pool.get().await?;
-        let stmt = WORLD_STMT.execute(&mut conn).await?;
-        db::db(conn, &self.rng, &stmt).await
+        let stmt = Exec::WORLD_STMT.execute(&mut conn).await?;
+        self.exec.db(conn, &stmt).await
     }
     }
 
 
     pub async fn queries(&self, num: u16) -> HandleResult<Vec<World>> {
     pub async fn queries(&self, num: u16) -> HandleResult<Vec<World>> {
         let mut conn = self.pool.get().await?;
         let mut conn = self.pool.get().await?;
-        let stmt = WORLD_STMT.execute(&mut conn).await?;
-        db::queries(conn, &self.rng, &stmt, num).await
+        let stmt = Exec::WORLD_STMT.execute(&mut conn).await?;
+        self.exec.queries(conn, &stmt, num).await
     }
     }
 
 
     pub async fn updates(&self, num: u16) -> HandleResult<Vec<World>> {
     pub async fn updates(&self, num: u16) -> HandleResult<Vec<World>> {
         let mut conn = self.pool.get().await?;
         let mut conn = self.pool.get().await?;
-        let world_stmt = WORLD_STMT.execute(&mut conn).await?;
-        let update_stmt = UPDATE_STMT.execute(&mut conn).await?;
-        db::updates(conn, &self.rng, &world_stmt, &update_stmt, num).await
+        let world_stmt = Exec::WORLD_STMT.execute(&mut conn).await?;
+        let update_stmt = Exec::UPDATE_STMT.execute(&mut conn).await?;
+        self.exec.updates(conn, &world_stmt, &update_stmt, num).await
     }
     }
 
 
     pub async fn fortunes(&self) -> HandleResult<Fortunes> {
     pub async fn fortunes(&self) -> HandleResult<Fortunes> {
         let mut conn = self.pool.get().await?;
         let mut conn = self.pool.get().await?;
-        let stmt = FORTUNE_STMT.execute(&mut conn).await?;
-        db::fortunes(conn, &stmt).await
+        let stmt = Exec::FORTUNE_STMT.execute(&mut conn).await?;
+        Exec::fortunes(conn, &stmt).await
     }
     }
 }
 }

+ 2 - 2
frameworks/Rust/xitca-web/src/db_toasty.rs

@@ -13,12 +13,12 @@ pub struct Pool {
 
 
 impl Pool {
 impl Pool {
     pub async fn create() -> HandleResult<Self> {
     pub async fn create() -> HandleResult<Self> {
-        let conn = xitca_postgres_toasty::PostgreSQL::connect(DB_URL).await?;
+        let drv = xitca_postgres_toasty::PostgreSQL::new(DB_URL)?;
 
 
         let db = Db::builder()
         let db = Db::builder()
             .register::<World>()
             .register::<World>()
             .register::<Fortune>()
             .register::<Fortune>()
-            .build(conn)
+            .build(drv)
             .await?;
             .await?;
 
 
         Ok(Self {
         Ok(Self {

+ 28 - 29
frameworks/Rust/xitca-web/src/db_unrealistic.rs

@@ -6,59 +6,58 @@ use core::future::Future;
 use xitca_postgres::{Execute, iter::AsyncLendingIterator, statement::Statement};
 use xitca_postgres::{Execute, iter::AsyncLendingIterator, statement::Statement};
 
 
 use super::{
 use super::{
+    db::Exec,
     ser::{Fortunes, World},
     ser::{Fortunes, World},
-    util::{DB_URL, HandleResult, Rand},
+    util::{DB_URL, HandleResult},
 };
 };
 
 
-use crate::db::{self, FORTUNE_STMT, UPDATE_STMT, WORLD_STMT};
-
 pub struct Client {
 pub struct Client {
     cli: xitca_postgres::Client,
     cli: xitca_postgres::Client,
-    rng: core::cell::RefCell<Rand>,
+    exec: Exec,
     fortune: Statement,
     fortune: Statement,
     world: Statement,
     world: Statement,
     update: Statement,
     update: Statement,
 }
 }
 
 
-pub async fn create() -> HandleResult<Client> {
-    let (cli, mut drv) = xitca_postgres::Postgres::new(DB_URL).connect().await?;
-
-    tokio::task::spawn(async move {
-        while drv.try_next().await?.is_some() {}
-        HandleResult::Ok(())
-    });
-
-    let world = WORLD_STMT.execute(&cli).await?.leak();
-    let fortune = FORTUNE_STMT.execute(&cli).await?.leak();
-    let update = UPDATE_STMT.execute(&cli).await?.leak();
-
-    Ok(Client {
-        cli,
-        rng: Default::default(),
-        world,
-        fortune,
-        update,
-    })
-}
-
 impl Client {
 impl Client {
+    pub async fn create() -> HandleResult<Self> {
+        let (cli, mut drv) = xitca_postgres::Postgres::new(DB_URL).connect().await?;
+
+        tokio::task::spawn(async move {
+            while drv.try_next().await?.is_some() {}
+            HandleResult::Ok(())
+        });
+
+        let world = Exec::WORLD_STMT.execute(&cli).await?.leak();
+        let fortune = Exec::FORTUNE_STMT.execute(&cli).await?.leak();
+        let update = Exec::UPDATE_STMT.execute(&cli).await?.leak();
+
+        Ok(Self {
+            cli,
+            exec: Default::default(),
+            world,
+            fortune,
+            update,
+        })
+    }
+
     #[inline]
     #[inline]
     pub fn db(&self) -> impl Future<Output = HandleResult<World>> {
     pub fn db(&self) -> impl Future<Output = HandleResult<World>> {
-        db::db(&self.cli, &self.rng, &self.world)
+        self.exec.db(&self.cli, &self.world)
     }
     }
 
 
     #[inline]
     #[inline]
     pub fn queries(&self, num: u16) -> impl Future<Output = HandleResult<Vec<World>>> {
     pub fn queries(&self, num: u16) -> impl Future<Output = HandleResult<Vec<World>>> {
-        db::queries(&self.cli, &self.rng, &self.world, num)
+        self.exec.queries(&self.cli, &self.world, num)
     }
     }
 
 
     #[inline]
     #[inline]
     pub fn updates(&self, num: u16) -> impl Future<Output = HandleResult<Vec<World>>> {
     pub fn updates(&self, num: u16) -> impl Future<Output = HandleResult<Vec<World>>> {
-        db::updates(&self.cli, &self.rng, &self.world, &self.update, num)
+        self.exec.updates(&self.cli, &self.world, &self.update, num)
     }
     }
 
 
     #[inline]
     #[inline]
     pub fn fortunes(&self) -> impl Future<Output = HandleResult<Fortunes>> {
     pub fn fortunes(&self) -> impl Future<Output = HandleResult<Fortunes>> {
-        db::fortunes(&self.cli, &self.fortune)
+        Exec::fortunes(&self.cli, &self.fortune)
     }
     }
 }
 }

+ 18 - 20
frameworks/Rust/xitca-web/src/main.rs

@@ -1,3 +1,8 @@
+// temporary allocator for tracking overhead between xitca-web and xitca-web [barebone] bench.
+// remove it before official run
+#[global_allocator]
+static GLOBAL: mimalloc::MiMalloc = mimalloc::MiMalloc;
+
 mod db;
 mod db;
 mod db_pool;
 mod db_pool;
 mod ser;
 mod ser;
@@ -18,60 +23,53 @@ use xitca_http::{
 use xitca_service::{Service, ServiceExt, fn_service};
 use xitca_service::{Service, ServiceExt, fn_service};
 
 
 use ser::{IntoResponse, Message, Request, Response, error_response};
 use ser::{IntoResponse, Message, Request, Response, error_response};
-use util::{QueryParse, SERVER_HEADER_VALUE, State};
+use util::{QueryParse, SERVER_HEADER_VALUE};
 
 
-type Ctx<'a> = Context<'a, Request<RequestBody>, State<db_pool::Client>>;
+type Ctx<'a> = Context<'a, Request<RequestBody>, db_pool::Client>;
 
 
 fn main() -> std::io::Result<()> {
 fn main() -> std::io::Result<()> {
     let service = Router::new()
     let service = Router::new()
         .insert(
         .insert(
             "/plaintext",
             "/plaintext",
-            get(fn_service(async |ctx: Ctx| ctx.into_parts().0.text_response())),
+            get(fn_service(async |ctx: Ctx| Ok(ctx.into_parts().0.text_response()))),
         )
         )
         .insert(
         .insert(
             "/json",
             "/json",
             get(fn_service(async |ctx: Ctx| {
             get(fn_service(async |ctx: Ctx| {
-                let (req, state) = ctx.into_parts();
-                req.json_response(state, &Message::new())
+                ctx.into_parts().0.json_response(&Message::new())
             })),
             })),
         )
         )
         .insert(
         .insert(
             "/db",
             "/db",
             get(fn_service(async |ctx: Ctx| {
             get(fn_service(async |ctx: Ctx| {
-                let (req, state) = ctx.into_parts();
-                let world = state.client.db().await?;
-                req.json_response(state, &world)
+                let (req, cli) = ctx.into_parts();
+                cli.db().await.and_then(|w| req.json_response(&w))
             })),
             })),
         )
         )
         .insert(
         .insert(
             "/fortunes",
             "/fortunes",
             get(fn_service(async |ctx: Ctx| {
             get(fn_service(async |ctx: Ctx| {
-                let (req, state) = ctx.into_parts();
-                let fortunes = state.client.fortunes().await?.render_once()?;
-                req.html_response(fortunes)
+                let (req, cli) = ctx.into_parts();
+                cli.fortunes().await?.render_once().map(|f| req.html_response(f))
             })),
             })),
         )
         )
         .insert(
         .insert(
             "/queries",
             "/queries",
             get(fn_service(async |ctx: Ctx| {
             get(fn_service(async |ctx: Ctx| {
-                let (req, state) = ctx.into_parts();
+                let (req, cli) = ctx.into_parts();
                 let num = req.uri().query().parse_query();
                 let num = req.uri().query().parse_query();
-                let worlds = state.client.queries(num).await?;
-                req.json_response(state, &worlds)
+                cli.queries(num).await.and_then(|w| req.json_response(&w))
             })),
             })),
         )
         )
         .insert(
         .insert(
             "/updates",
             "/updates",
             get(fn_service(async |ctx: Ctx| {
             get(fn_service(async |ctx: Ctx| {
-                let (req, state) = ctx.into_parts();
+                let (req, cli) = ctx.into_parts();
                 let num = req.uri().query().parse_query();
                 let num = req.uri().query().parse_query();
-                let worlds = state.client.updates(num).await?;
-                req.json_response(state, &worlds)
+                cli.updates(num).await.and_then(|w| req.json_response(&w))
             })),
             })),
         )
         )
-        .enclosed(ContextBuilder::new(|| async {
-            db_pool::create().await.map(State::new)
-        }))
+        .enclosed(ContextBuilder::new(db_pool::Client::create))
         .enclosed_fn(async |service, req| {
         .enclosed_fn(async |service, req| {
             let mut res = service.call(req).await.unwrap_or_else(error_handler);
             let mut res = service.call(req).await.unwrap_or_else(error_handler);
             res.headers_mut().insert(SERVER, SERVER_HEADER_VALUE);
             res.headers_mut().insert(SERVER, SERVER_HEADER_VALUE);

+ 17 - 23
frameworks/Rust/xitca-web/src/main_barebone.rs

@@ -19,10 +19,7 @@ use xitca_http::{
 };
 };
 use xitca_service::Service;
 use xitca_service::Service;
 
 
-use self::{
-    ser::Message,
-    util::{QueryParse, State},
-};
+use self::{ser::Message, util::QueryParse};
 
 
 fn main() -> io::Result<()> {
 fn main() -> io::Result<()> {
     let addr = "0.0.0.0:8080".parse().unwrap();
     let addr = "0.0.0.0:8080".parse().unwrap();
@@ -51,10 +48,10 @@ fn main() -> io::Result<()> {
                 socket.bind(addr)?;
                 socket.bind(addr)?;
                 let listener = socket.listen(1024)?;
                 let listener = socket.listen(1024)?;
 
 
-                let client = db_unrealistic::create().await.unwrap();
+                let client = db_unrealistic::Client::create().await.unwrap();
 
 
                 // unrealistic http dispatcher. no spec check. no security feature.
                 // unrealistic http dispatcher. no spec check. no security feature.
-                let service = Dispatcher::new(handler, State::new(client));
+                let service = Dispatcher::new(handler, client);
 
 
                 loop {
                 loop {
                     match listener.accept().await {
                     match listener.accept().await {
@@ -81,13 +78,13 @@ fn main() -> io::Result<()> {
     // need clean async shutdown will be leaked.
     // need clean async shutdown will be leaked.
     worker(ids.pop())?;
     worker(ids.pop())?;
     for handle in handle {
     for handle in handle {
-        handle.join().unwrap()?;
+        let _ = handle.join().unwrap();
     }
     }
 
 
     Ok(())
     Ok(())
 }
 }
 
 
-async fn handler<'h>(req: Request<'h, State<db_unrealistic::Client>>, res: Response<'h>) -> Response<'h, 3> {
+async fn handler<'h>(req: Request<'h, db_unrealistic::Client>, res: Response<'h>) -> Response<'h, 3> {
     // unrealistic due to no http method check
     // unrealistic due to no http method check
     match req.path {
     match req.path {
         // unrealistic due to no dynamic path matching
         // unrealistic due to no dynamic path matching
@@ -112,7 +109,7 @@ async fn handler<'h>(req: Request<'h, State<db_unrealistic::Client>>, res: Respo
 
 
         // all database related categories are unrealistic. please reference db_unrealistic module for detail.
         // all database related categories are unrealistic. please reference db_unrealistic module for detail.
         "/fortunes" => {
         "/fortunes" => {
-            let fortunes = req.ctx.client.fortunes().await.unwrap().render_once().unwrap();
+            let fortunes = req.ctx.fortunes().await.unwrap().render_once().unwrap();
             res.status(StatusCode::OK)
             res.status(StatusCode::OK)
                 .header("content-type", "text/html; charset=utf-8")
                 .header("content-type", "text/html; charset=utf-8")
                 .header("server", "X")
                 .header("server", "X")
@@ -121,34 +118,31 @@ async fn handler<'h>(req: Request<'h, State<db_unrealistic::Client>>, res: Respo
         "/db" => {
         "/db" => {
             // unrealistic due to no error handling. any db/serialization error will cause process crash.
             // unrealistic due to no error handling. any db/serialization error will cause process crash.
             // the same goes for all following unwraps on database related functions.
             // the same goes for all following unwraps on database related functions.
-            let world = req.ctx.client.db().await.unwrap();
-            json_response(res, req.ctx, &world)
+            let world = req.ctx.db().await.unwrap();
+            json_response(res, &world)
         }
         }
         p if p.starts_with("/q") => {
         p if p.starts_with("/q") => {
             let num = p["/queries?q=".len()..].parse_query();
             let num = p["/queries?q=".len()..].parse_query();
-            let worlds = req.ctx.client.queries(num).await.unwrap();
-            json_response(res, req.ctx, &worlds)
+            let worlds = req.ctx.queries(num).await.unwrap();
+            json_response(res, &worlds)
         }
         }
         p if p.starts_with("/u") => {
         p if p.starts_with("/u") => {
             let num = p["/updates?q=".len()..].parse_query();
             let num = p["/updates?q=".len()..].parse_query();
-            let worlds = req.ctx.client.updates(num).await.unwrap();
-            json_response(res, req.ctx, &worlds)
+            let worlds = req.ctx.updates(num).await.unwrap();
+            json_response(res, &worlds)
         }
         }
         _ => res.status(StatusCode::NOT_FOUND).header("server", "X").body(&[]),
         _ => res.status(StatusCode::NOT_FOUND).header("server", "X").body(&[]),
     }
     }
 }
 }
 
 
-fn json_response<'r, DB, T>(res: Response<'r>, state: &State<DB>, val: &T) -> Response<'r, 3>
+fn json_response<'r, T>(res: Response<'r>, val: &T) -> Response<'r, 3>
 where
 where
     T: serde_core::Serialize,
     T: serde_core::Serialize,
 {
 {
-    let buf = &mut *state.write_buf.borrow_mut();
-    sonic_rs::to_writer(buf.writer(), val).unwrap();
-    let res = res
-        .status(StatusCode::OK)
+    let mut buf = xitca_http::bytes::BytesMut::new();
+    sonic_rs::to_writer((&mut buf).writer(), val).unwrap();
+    res.status(StatusCode::OK)
         .header("content-type", "application/json")
         .header("content-type", "application/json")
         .header("server", "X")
         .header("server", "X")
-        .body(buf.as_ref());
-    buf.clear();
-    res
+        .body(buf.as_ref())
 }
 }

+ 23 - 25
frameworks/Rust/xitca-web/src/ser.rs

@@ -71,11 +71,18 @@ pub struct Fortunes {
     items: Vec<Fortune>,
     items: Vec<Fortune>,
 }
 }
 
 
-// this is roughly the code generated by sailfish::TemplateOnce macro.
-// using the macro does not have any perf cost and this piece of code is expanded manually to speed up compile time of
-// bench to reduce resource usage of bench runner
-#[cfg(feature = "template")]
 impl Fortunes {
 impl Fortunes {
+    #[inline]
+    pub fn new(mut items: Vec<Fortune>) -> Self {
+        items.push(Fortune::new(0, "Additional fortune added at request time."));
+        items.sort_by(|a, b| a.message.cmp(&b.message));
+        Self { items }
+    }
+
+    // this is roughly the code generated by sailfish::TemplateOnce macro.
+    // using the macro does not have any perf cost and this piece of code is expanded manually to speed up compile time of
+    // bench to reduce resource usage of bench runner
+    #[cfg(feature = "template")]
     pub fn render_once(self) -> HandleResult<String> {
     pub fn render_once(self) -> HandleResult<String> {
         use sailfish::runtime::{Buffer, Render};
         use sailfish::runtime::{Buffer, Render};
 
 
@@ -98,15 +105,6 @@ impl Fortunes {
     }
     }
 }
 }
 
 
-impl Fortunes {
-    #[inline]
-    pub fn new(mut items: Vec<Fortune>) -> Self {
-        items.push(Fortune::new(0, "Additional fortune added at request time."));
-        items.sort_by(|a, b| a.message.cmp(&b.message));
-        Self { items }
-    }
-}
-
 impl<'de> Deserialize<'de> for Num {
 impl<'de> Deserialize<'de> for Num {
     fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
     fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
     where
     where
@@ -199,39 +197,39 @@ pub type Response = http::Response<Once<Bytes>>;
 
 
 pub trait IntoResponse: Sized {
 pub trait IntoResponse: Sized {
     #[cfg(any(feature = "json", feature = "perf-json"))]
     #[cfg(any(feature = "json", feature = "perf-json"))]
-    fn json_response<C>(self, state: &crate::util::State<C>, val: &impl Serialize) -> HandleResult<Response>;
+    fn json_response(self, val: &impl Serialize) -> HandleResult<Response>;
 
 
-    fn text_response(self) -> HandleResult<Response>;
+    fn text_response(self) -> Response;
 
 
-    fn html_response(self, val: String) -> HandleResult<Response>;
+    fn html_response(self, val: String) -> Response;
 }
 }
 
 
 impl<Ext> IntoResponse for Request<Ext> {
 impl<Ext> IntoResponse for Request<Ext> {
     #[cfg(any(feature = "json", feature = "perf-json"))]
     #[cfg(any(feature = "json", feature = "perf-json"))]
-    fn json_response<C>(self, state: &crate::util::State<C>, val: &impl Serialize) -> HandleResult<Response> {
-        let buf = &mut *state.write_buf.borrow_mut();
+    fn json_response(self, val: &impl Serialize) -> HandleResult<Response> {
+        let mut buf = xitca_http::bytes::BytesMut::new();
         #[cfg(all(feature = "json", not(feature = "perf-json")))]
         #[cfg(all(feature = "json", not(feature = "perf-json")))]
-        serde_json::to_writer(xitca_http::bytes::BufMutWriter(buf), val)?;
+        serde_json::to_writer(xitca_http::bytes::BufMutWriter(&mut buf), val)?;
 
 
         #[cfg(all(feature = "perf-json", not(feature = "json")))]
         #[cfg(all(feature = "perf-json", not(feature = "json")))]
-        sonic_rs::to_writer(xitca_http::bytes::BufMut::writer(&mut *buf), val)?;
+        sonic_rs::to_writer(xitca_http::bytes::BufMut::writer(&mut buf), val)?;
 
 
-        let mut res = self.into_response(buf.split().freeze());
+        let mut res = self.into_response(buf.freeze());
         res.headers_mut()
         res.headers_mut()
             .insert(CONTENT_TYPE, xitca_http::http::const_header_value::JSON);
             .insert(CONTENT_TYPE, xitca_http::http::const_header_value::JSON);
         Ok(res)
         Ok(res)
     }
     }
 
 
-    fn text_response(self) -> HandleResult<Response> {
+    fn text_response(self) -> Response {
         let mut res = self.into_response(const { Bytes::from_static(HELLO_BYTES) });
         let mut res = self.into_response(const { Bytes::from_static(HELLO_BYTES) });
         res.headers_mut().insert(CONTENT_TYPE, TEXT_UTF8);
         res.headers_mut().insert(CONTENT_TYPE, TEXT_UTF8);
-        Ok(res)
+        res
     }
     }
 
 
-    fn html_response(self, val: String) -> HandleResult<Response> {
+    fn html_response(self, val: String) -> Response {
         let mut res = self.into_response(Bytes::from(val));
         let mut res = self.into_response(Bytes::from(val));
         res.headers_mut().insert(CONTENT_TYPE, TEXT_HTML_UTF8);
         res.headers_mut().insert(CONTENT_TYPE, TEXT_HTML_UTF8);
-        Ok(res)
+        res
     }
     }
 }
 }
 
 

+ 1 - 15
frameworks/Rust/xitca-web/src/util.rs

@@ -1,7 +1,7 @@
 #![allow(dead_code)]
 #![allow(dead_code)]
 
 
 use rand::{Rng, SeedableRng, distr::Uniform, rngs::SmallRng};
 use rand::{Rng, SeedableRng, distr::Uniform, rngs::SmallRng};
-use xitca_http::{bytes::BytesMut, http::header::HeaderValue};
+use xitca_http::http::header::HeaderValue;
 
 
 pub trait QueryParse {
 pub trait QueryParse {
     fn parse_query(self) -> u16;
     fn parse_query(self) -> u16;
@@ -30,20 +30,6 @@ pub type HandleResult<T> = Result<T, Error>;
 
 
 pub const DB_URL: &str = "postgres://benchmarkdbuser:benchmarkdbpass@tfb-database/hello_world";
 pub const DB_URL: &str = "postgres://benchmarkdbuser:benchmarkdbpass@tfb-database/hello_world";
 
 
-pub struct State<DB> {
-    pub client: DB,
-    pub write_buf: core::cell::RefCell<BytesMut>,
-}
-
-impl<DB> State<DB> {
-    pub fn new(client: DB) -> Self {
-        Self {
-            client,
-            write_buf: Default::default(),
-        }
-    }
-}
-
 pub struct Rand(SmallRng);
 pub struct Rand(SmallRng);
 
 
 impl Default for Rand {
 impl Default for Rand {

+ 1 - 1
frameworks/Rust/xitca-web/xitca-web.dockerfile

@@ -3,7 +3,7 @@ FROM rust:1.92
 ADD ./ /xitca-web
 ADD ./ /xitca-web
 WORKDIR /xitca-web
 WORKDIR /xitca-web
 
 
-RUN cargo build --release --bin xitca-web --features io-uring,json,pg,router,template
+RUN cargo build --release --bin xitca-web --features io-uring,pg,router,template,perf-json,perf-allocator
 
 
 EXPOSE 8080
 EXPOSE 8080