Browse Source

[xitca-web] reduce memory allocation (#10343)

* [xitca-web] reduce memory allocation

* generate rng with iterator

* clean up module layout
fakeshadow 2 weeks ago
parent
commit
90025728d3

+ 39 - 39
frameworks/Rust/xitca-web/Cargo.lock

@@ -151,9 +151,9 @@ checksum = "b35204fbdc0b3f4446b89fc1ac2cf84a8a68971995d0bf2e925ec7cd960f9cb3"
 
 
 [[package]]
 [[package]]
 name = "cc"
 name = "cc"
-version = "1.2.47"
+version = "1.2.48"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cd405d82c84ff7f35739f175f67d8b9fb7687a0e84ccdc78bd3568839827cf07"
+checksum = "c481bdbf0ed3b892f6f806287d72acd515b352a4ec27a208489b8c1bc839633a"
 dependencies = [
 dependencies = [
  "find-msvc-tools",
  "find-msvc-tools",
  "shlex",
  "shlex",
@@ -232,9 +232,9 @@ dependencies = [
 
 
 [[package]]
 [[package]]
 name = "diesel"
 name = "diesel"
-version = "2.3.3"
+version = "2.3.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5e7624a3bb9fffd82fff016be9a7f163d20e5a89eb8d28f9daaa6b30fff37500"
+checksum = "0c415189028b232660655e4893e8bc25ca7aee8e96888db66d9edb400535456a"
 dependencies = [
 dependencies = [
  "bitflags 2.10.0",
  "bitflags 2.10.0",
  "byteorder",
  "byteorder",
@@ -261,9 +261,9 @@ dependencies = [
 
 
 [[package]]
 [[package]]
 name = "diesel_derives"
 name = "diesel_derives"
-version = "2.3.4"
+version = "2.3.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9daac6489a36e42570da165a10c424f3edcefdff70c5fd55e1847c23f3dd7562"
+checksum = "8587cbca3c929fb198e7950d761d31ca72b80aa6e07c1b7bec5879d187720436"
 dependencies = [
 dependencies = [
  "diesel_table_macro_syntax",
  "diesel_table_macro_syntax",
  "dsl_auto_type",
  "dsl_auto_type",
@@ -664,9 +664,9 @@ checksum = "9028f49264629065d057f340a86acb84867925865f73bbf8d47b4d149a7e88b8"
 
 
 [[package]]
 [[package]]
 name = "js-sys"
 name = "js-sys"
-version = "0.3.82"
+version = "0.3.83"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b011eec8cc36da2aab2d5cff675ec18454fad408585853910a202391cf9f8e65"
+checksum = "464a3709c7f55f1f721e5389aa6ea4e3bc6aba669353300af094b29ffbdde1d8"
 dependencies = [
 dependencies = [
  "once_cell",
  "once_cell",
  "wasm-bindgen",
  "wasm-bindgen",
@@ -1281,7 +1281,7 @@ checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596"
 [[package]]
 [[package]]
 name = "std-util"
 name = "std-util"
 version = "0.1.0"
 version = "0.1.0"
-source = "git+https://github.com/tokio-rs/toasty?rev=e0c84c5#e0c84c5182cfd3aca16b2f77145dd0946a4cb223"
+source = "git+https://github.com/fakeshadow/toasty?branch=engine#adff354a113ae85dd26a5fd8cecc2807fa12d5bf"
 dependencies = [
 dependencies = [
  "heck",
  "heck",
  "pluralizer",
  "pluralizer",
@@ -1381,7 +1381,7 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
 [[package]]
 [[package]]
 name = "toasty"
 name = "toasty"
 version = "0.1.0"
 version = "0.1.0"
-source = "git+https://github.com/tokio-rs/toasty?rev=e0c84c5#e0c84c5182cfd3aca16b2f77145dd0946a4cb223"
+source = "git+https://github.com/fakeshadow/toasty?branch=engine#adff354a113ae85dd26a5fd8cecc2807fa12d5bf"
 dependencies = [
 dependencies = [
  "anyhow",
  "anyhow",
  "async-stream",
  "async-stream",
@@ -1399,7 +1399,7 @@ dependencies = [
 [[package]]
 [[package]]
 name = "toasty-codegen"
 name = "toasty-codegen"
 version = "0.1.0"
 version = "0.1.0"
-source = "git+https://github.com/tokio-rs/toasty?rev=e0c84c5#e0c84c5182cfd3aca16b2f77145dd0946a4cb223"
+source = "git+https://github.com/fakeshadow/toasty?branch=engine#adff354a113ae85dd26a5fd8cecc2807fa12d5bf"
 dependencies = [
 dependencies = [
  "proc-macro2",
  "proc-macro2",
  "quote",
  "quote",
@@ -1410,7 +1410,7 @@ dependencies = [
 [[package]]
 [[package]]
 name = "toasty-core"
 name = "toasty-core"
 version = "0.1.0"
 version = "0.1.0"
-source = "git+https://github.com/tokio-rs/toasty?rev=e0c84c5#e0c84c5182cfd3aca16b2f77145dd0946a4cb223"
+source = "git+https://github.com/fakeshadow/toasty?branch=engine#adff354a113ae85dd26a5fd8cecc2807fa12d5bf"
 dependencies = [
 dependencies = [
  "anyhow",
  "anyhow",
  "async-trait",
  "async-trait",
@@ -1424,7 +1424,7 @@ dependencies = [
 [[package]]
 [[package]]
 name = "toasty-macros"
 name = "toasty-macros"
 version = "0.1.0"
 version = "0.1.0"
-source = "git+https://github.com/tokio-rs/toasty?rev=e0c84c5#e0c84c5182cfd3aca16b2f77145dd0946a4cb223"
+source = "git+https://github.com/fakeshadow/toasty?branch=engine#adff354a113ae85dd26a5fd8cecc2807fa12d5bf"
 dependencies = [
 dependencies = [
  "proc-macro2",
  "proc-macro2",
  "quote",
  "quote",
@@ -1436,7 +1436,7 @@ dependencies = [
 [[package]]
 [[package]]
 name = "toasty-sql"
 name = "toasty-sql"
 version = "0.1.0"
 version = "0.1.0"
-source = "git+https://github.com/tokio-rs/toasty?rev=e0c84c5#e0c84c5182cfd3aca16b2f77145dd0946a4cb223"
+source = "git+https://github.com/fakeshadow/toasty?branch=engine#adff354a113ae85dd26a5fd8cecc2807fa12d5bf"
 dependencies = [
 dependencies = [
  "anyhow",
  "anyhow",
  "toasty-core",
  "toasty-core",
@@ -1537,9 +1537,9 @@ dependencies = [
 
 
 [[package]]
 [[package]]
 name = "tracing"
 name = "tracing"
-version = "0.1.41"
+version = "0.1.43"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0"
+checksum = "2d15d90a0b5c19378952d479dc858407149d7bb45a14de0142f6c534b16fc647"
 dependencies = [
 dependencies = [
  "pin-project-lite",
  "pin-project-lite",
  "tracing-core",
  "tracing-core",
@@ -1547,9 +1547,9 @@ dependencies = [
 
 
 [[package]]
 [[package]]
 name = "tracing-core"
 name = "tracing-core"
-version = "0.1.34"
+version = "0.1.35"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678"
+checksum = "7a04e24fab5c89c6a36eb8558c9656f30d81de51dfa4d3b45f26b21d61fa0a6c"
 
 
 [[package]]
 [[package]]
 name = "typenum"
 name = "typenum"
@@ -1661,9 +1661,9 @@ checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b"
 
 
 [[package]]
 [[package]]
 name = "wasm-bindgen"
 name = "wasm-bindgen"
-version = "0.2.105"
+version = "0.2.106"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "da95793dfc411fbbd93f5be7715b0578ec61fe87cb1a42b12eb625caa5c5ea60"
+checksum = "0d759f433fa64a2d763d1340820e46e111a7a5ab75f993d1852d70b03dbb80fd"
 dependencies = [
 dependencies = [
  "cfg-if",
  "cfg-if",
  "once_cell",
  "once_cell",
@@ -1674,9 +1674,9 @@ dependencies = [
 
 
 [[package]]
 [[package]]
 name = "wasm-bindgen-macro"
 name = "wasm-bindgen-macro"
-version = "0.2.105"
+version = "0.2.106"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "04264334509e04a7bf8690f2384ef5265f05143a4bff3889ab7a3269adab59c2"
+checksum = "48cb0d2638f8baedbc542ed444afc0644a29166f1595371af4fecf8ce1e7eeb3"
 dependencies = [
 dependencies = [
  "quote",
  "quote",
  "wasm-bindgen-macro-support",
  "wasm-bindgen-macro-support",
@@ -1684,9 +1684,9 @@ dependencies = [
 
 
 [[package]]
 [[package]]
 name = "wasm-bindgen-macro-support"
 name = "wasm-bindgen-macro-support"
-version = "0.2.105"
+version = "0.2.106"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "420bc339d9f322e562942d52e115d57e950d12d88983a14c79b86859ee6c7ebc"
+checksum = "cefb59d5cd5f92d9dcf80e4683949f15ca4b511f4ac0a6e14d4e1ac60c6ecd40"
 dependencies = [
 dependencies = [
  "bumpalo",
  "bumpalo",
  "proc-macro2",
  "proc-macro2",
@@ -1697,18 +1697,18 @@ dependencies = [
 
 
 [[package]]
 [[package]]
 name = "wasm-bindgen-shared"
 name = "wasm-bindgen-shared"
-version = "0.2.105"
+version = "0.2.106"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "76f218a38c84bcb33c25ec7059b07847d465ce0e0a76b995e134a45adcb6af76"
+checksum = "cbc538057e648b67f72a982e708d485b2efa771e1ac05fec311f9f63e5800db4"
 dependencies = [
 dependencies = [
  "unicode-ident",
  "unicode-ident",
 ]
 ]
 
 
 [[package]]
 [[package]]
 name = "web-sys"
 name = "web-sys"
-version = "0.3.82"
+version = "0.3.83"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3a1f95c0d03a47f4ae1f7a64643a6bb97465d9b740f0fa8f90ea33915c99a9a1"
+checksum = "9b32828d774c412041098d182a8b38b16ea816958e07cf40eec2bc080ae137ac"
 dependencies = [
 dependencies = [
  "js-sys",
  "js-sys",
  "wasm-bindgen",
  "wasm-bindgen",
@@ -1851,7 +1851,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=c9c4b25#c9c4b259e7e7a903f494dd54a6be6073363430c4"
+source = "git+http://github.com/HFQR/xitca-web?rev=cf70ed7#cf70ed7328c1b6d60c339a7dc67be454f59b1736"
 dependencies = [
 dependencies = [
  "quote",
  "quote",
  "syn",
  "syn",
@@ -1860,7 +1860,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=c9c4b25#c9c4b259e7e7a903f494dd54a6be6073363430c4"
+source = "git+http://github.com/HFQR/xitca-web?rev=cf70ed7#cf70ed7328c1b6d60c339a7dc67be454f59b1736"
 dependencies = [
 dependencies = [
  "futures-core",
  "futures-core",
  "http",
  "http",
@@ -1893,7 +1893,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=c9c4b25#c9c4b259e7e7a903f494dd54a6be6073363430c4"
+source = "git+http://github.com/HFQR/xitca-web?rev=cf70ed7#cf70ed7328c1b6d60c339a7dc67be454f59b1736"
 dependencies = [
 dependencies = [
  "fallible-iterator",
  "fallible-iterator",
  "futures-core",
  "futures-core",
@@ -1909,7 +1909,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=8ce4e5b#8ce4e5bb138765bc1780642adfefc4d3b8427bb7"
+source = "git+https://github.com/fakeshadow/xitca-postgres-diesel?rev=7671975#7671975951fdd71bfaedaa1686aa7c69e4af6caf"
 dependencies = [
 dependencies = [
  "diesel",
  "diesel",
  "diesel-async",
  "diesel-async",
@@ -1946,7 +1946,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=c9c4b25#c9c4b259e7e7a903f494dd54a6be6073363430c4"
+source = "git+http://github.com/HFQR/xitca-web?rev=cf70ed7#cf70ed7328c1b6d60c339a7dc67be454f59b1736"
 dependencies = [
 dependencies = [
  "socket2 0.6.1",
  "socket2 0.6.1",
  "tokio",
  "tokio",
@@ -1960,7 +1960,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=c9c4b25#c9c4b259e7e7a903f494dd54a6be6073363430c4"
+source = "git+http://github.com/HFQR/xitca-web?rev=cf70ed7#cf70ed7328c1b6d60c339a7dc67be454f59b1736"
 
 
 [[package]]
 [[package]]
 name = "xitca-unsafe-collection"
 name = "xitca-unsafe-collection"
@@ -2006,7 +2006,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=c9c4b25#c9c4b259e7e7a903f494dd54a6be6073363430c4"
+source = "git+http://github.com/HFQR/xitca-web?rev=cf70ed7#cf70ed7328c1b6d60c339a7dc67be454f59b1736"
 dependencies = [
 dependencies = [
  "futures-core",
  "futures-core",
  "pin-project-lite",
  "pin-project-lite",
@@ -2046,18 +2046,18 @@ dependencies = [
 
 
 [[package]]
 [[package]]
 name = "zerocopy"
 name = "zerocopy"
-version = "0.8.30"
+version = "0.8.31"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4ea879c944afe8a2b25fef16bb4ba234f47c694565e97383b36f3a878219065c"
+checksum = "fd74ec98b9250adb3ca554bdde269adf631549f51d8a8f8f0a10b50f1cb298c3"
 dependencies = [
 dependencies = [
  "zerocopy-derive",
  "zerocopy-derive",
 ]
 ]
 
 
 [[package]]
 [[package]]
 name = "zerocopy-derive"
 name = "zerocopy-derive"
-version = "0.8.30"
+version = "0.8.31"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cf955aa904d6040f70dc8e9384444cb1030aed272ba3cb09bbc4ab9e7c1f34f5"
+checksum = "d8a8d209fdf45cf5138cbb5a506f6b52522a25afccc534d1475dad8e31105c6a"
 dependencies = [
 dependencies = [
  "proc-macro2",
  "proc-macro2",
  "quote",
  "quote",

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

@@ -29,7 +29,7 @@ pg = ["dep:xitca-postgres"]
 # diesel orm optional
 # diesel orm optional
 diesel = ["dep:diesel", "dep:diesel-async", "dep:xitca-postgres-diesel", "dep:futures-util"]
 diesel = ["dep:diesel", "dep:diesel-async", "dep:xitca-postgres-diesel", "dep:futures-util"]
 # toasty orm optional
 # toasty orm optional
-toasty = ["dep:toasty", "dep:xitca-postgres-toasty"]
+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 optional
@@ -64,7 +64,7 @@ xitca-postgres = { version = "0.3", optional = true }
 # diesel orm optional
 # diesel orm optional
 diesel = { version = "2", features = ["postgres"], optional = true }
 diesel = { version = "2", features = ["postgres"], optional = true }
 diesel-async = { version = "0.7", features = ["bb8", "postgres"], optional = true }
 diesel-async = { version = "0.7", features = ["bb8", "postgres"], optional = true }
-xitca-postgres-diesel = { version = "0.2", optional = true }
+xitca-postgres-diesel = { version = "0.2", default-features = false, optional = true }
 futures-util = { version = "0.3", default-features = false, optional = true }
 futures-util = { version = "0.3", default-features = false, optional = true }
 
 
 # toasty orm optional
 # toasty orm optional
@@ -94,16 +94,17 @@ 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 = "8ce4e5b" }
+xitca-postgres-diesel = { git = "https://github.com/fakeshadow/xitca-postgres-diesel", rev = "7671975" }
 xitca-postgres-toasty = { git = "https://github.com/fakeshadow/xitca-postgres-toasty", rev = "04bedb8" }
 xitca-postgres-toasty = { git = "https://github.com/fakeshadow/xitca-postgres-toasty", rev = "04bedb8" }
 
 
-toasty = { git = "https://github.com/tokio-rs/toasty", rev = "e0c84c5" }
-toasty-core = { git = "https://github.com/tokio-rs/toasty", rev = "e0c84c5" }
-toasty-sql = { git = "https://github.com/tokio-rs/toasty", rev = "e0c84c5" }
-
-xitca-codegen = { git = "http://github.com/HFQR/xitca-web", rev = "c9c4b25" }
-xitca-http = { git = "http://github.com/HFQR/xitca-web", rev = "c9c4b25" }
-xitca-postgres = { git = "http://github.com/HFQR/xitca-web", rev = "c9c4b25" }
-xitca-server = { git = "http://github.com/HFQR/xitca-web", rev = "c9c4b25" }
-xitca-service = { git = "http://github.com/HFQR/xitca-web", rev = "c9c4b25" }
-xitca-web = { git = "http://github.com/HFQR/xitca-web", rev = "c9c4b25" }
+# personal fork for efficient toasty engine fine tuned with pipelined xitca-postgres client
+toasty = { 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" }
+
+xitca-codegen = { git = "http://github.com/HFQR/xitca-web", rev = "cf70ed7" }
+xitca-http = { git = "http://github.com/HFQR/xitca-web", rev = "cf70ed7" }
+xitca-postgres = { git = "http://github.com/HFQR/xitca-web", rev = "cf70ed7" }
+xitca-server = { git = "http://github.com/HFQR/xitca-web", rev = "cf70ed7" }
+xitca-service = { git = "http://github.com/HFQR/xitca-web", rev = "cf70ed7" }
+xitca-web = { git = "http://github.com/HFQR/xitca-web", rev = "cf70ed7" }

+ 21 - 23
frameworks/Rust/xitca-web/src/db.rs

@@ -10,7 +10,7 @@ use super::{
     util::{DB_URL, HandleResult},
     util::{DB_URL, HandleResult},
 };
 };
 
 
-use db_util::{FORTUNE_STMT, Shared, UPDATE_BATCH_STMT, WORLD_STMT, not_found};
+use db_util::{FORTUNE_STMT, Shared, UPDATE_STMT, WORLD_STMT, not_found};
 
 
 pub struct Client {
 pub struct Client {
     pool: Pool,
     pool: Pool,
@@ -35,19 +35,19 @@ impl Client {
     }
     }
 
 
     pub async fn get_worlds(&self, num: u16) -> HandleResult<Vec<World>> {
     pub async fn get_worlds(&self, num: u16) -> HandleResult<Vec<World>> {
-        let len = num as usize;
-
         let mut conn = self.pool.get().await?;
         let mut conn = self.pool.get().await?;
         let stmt = WORLD_STMT.execute(&mut conn).await?;
         let stmt = WORLD_STMT.execute(&mut conn).await?;
 
 
         let mut res = {
         let mut res = {
             let (ref mut rng, ref mut buf) = *self.shared.borrow_mut();
             let (ref mut rng, ref mut buf) = *self.shared.borrow_mut();
-            let mut pipe = Pipeline::with_capacity_from_buf(len, buf);
-            (0..num).try_for_each(|_| stmt.bind([rng.gen_id()]).query(&mut pipe))?;
+            let mut pipe = Pipeline::with_capacity_from_buf(num as _, buf);
+            rng.gen_multi()
+                .take(num as _)
+                .try_for_each(|id| stmt.bind([id]).query(&mut pipe))?;
             pipe.query(&conn.consume())?
             pipe.query(&conn.consume())?
         };
         };
 
 
-        let mut worlds = Vec::with_capacity(len);
+        let mut worlds = Vec::with_capacity(num as _);
 
 
         while let Some(mut item) = res.try_next().await? {
         while let Some(mut item) = res.try_next().await? {
             let row = item.try_next().await?.ok_or_else(not_found)?;
             let row = item.try_next().await?.ok_or_else(not_found)?;
@@ -58,28 +58,26 @@ impl Client {
     }
     }
 
 
     pub async fn update(&self, num: u16) -> HandleResult<Vec<World>> {
     pub async fn update(&self, num: u16) -> HandleResult<Vec<World>> {
-        let len = num as usize;
-
         let mut conn = self.pool.get().await?;
         let mut conn = self.pool.get().await?;
         let world_stmt = WORLD_STMT.execute(&mut conn).await?;
         let world_stmt = WORLD_STMT.execute(&mut conn).await?;
-        let update_stmt = UPDATE_BATCH_STMT.execute(&mut conn).await?;
+        let update_stmt = UPDATE_STMT.execute(&mut conn).await?;
 
 
         let (mut res, worlds) = {
         let (mut res, worlds) = {
             let (ref mut rng, ref mut buf) = *self.shared.borrow_mut();
             let (ref mut rng, ref mut buf) = *self.shared.borrow_mut();
-            let mut pipe = Pipeline::with_capacity_from_buf(len + 1, buf);
-
-            let (mut params, worlds) = core::iter::repeat_with(|| {
-                let id = rng.gen_id();
-                let rand = rng.gen_id();
-                world_stmt.bind([id]).query(&mut pipe)?;
-                HandleResult::Ok(((id, rand), World::new(id, rand)))
-            })
-            .take(len)
-            .collect::<Result<(Vec<_>, Vec<_>), _>>()?;
-
-            params.sort();
-            let (ids, rngs) = params.into_iter().collect::<(Vec<_>, Vec<_>)>();
-
+            let mut pipe = Pipeline::with_capacity_from_buf((num + 1) as _, buf);
+
+            let mut ids = rng.gen_multi().take(num as _).collect::<Vec<_>>();
+            ids.sort();
+
+            let (rngs, worlds) = ids
+                .iter()
+                .cloned()
+                .zip(rng.gen_multi())
+                .map(|(id, rand)| {
+                    world_stmt.bind([id]).query(&mut pipe)?;
+                    HandleResult::Ok((rand, World::new(id, rand)))
+                })
+                .collect::<HandleResult<(Vec<_>, Vec<_>)>>()?;
             update_stmt.bind([&ids, &rngs]).query(&mut pipe)?;
             update_stmt.bind([&ids, &rngs]).query(&mut pipe)?;
             (pipe.query(&conn.consume())?, worlds)
             (pipe.query(&conn.consume())?, worlds)
         };
         };

+ 92 - 60
frameworks/Rust/xitca-web/src/db_diesel.rs

@@ -1,48 +1,39 @@
-#[path = "./db_util.rs"]
-mod db_util;
-
-use core::cell::RefCell;
-
-use std::io;
-
 use diesel::prelude::*;
 use diesel::prelude::*;
 use diesel_async::{
 use diesel_async::{
     RunQueryDsl,
     RunQueryDsl,
     pooled_connection::{AsyncDieselConnectionManager, bb8},
     pooled_connection::{AsyncDieselConnectionManager, bb8},
 };
 };
-use futures_util::future::{TryFutureExt, try_join, try_join_all};
+use futures_util::future::{TryFutureExt, TryJoinAll, try_join};
 use xitca_postgres_diesel::AsyncPgConnection;
 use xitca_postgres_diesel::AsyncPgConnection;
 
 
 use crate::{
 use crate::{
-    ser::{Fortune, Fortunes, World},
+    ser::{Fortunes, World},
     util::{DB_URL, HandleResult, Rand},
     util::{DB_URL, HandleResult, Rand},
 };
 };
 
 
-use db_util::update_query_from_ids;
-
 pub struct Pool {
 pub struct Pool {
     pool: bb8::Pool<AsyncPgConnection>,
     pool: bb8::Pool<AsyncPgConnection>,
-    rng: RefCell<Rand>,
+    rng: core::cell::RefCell<Rand>,
 }
 }
 
 
-pub async fn create() -> io::Result<Pool> {
-    bb8::Pool::builder()
-        .max_size(1)
-        .min_idle(Some(1))
-        .test_on_check_out(false)
-        .build(AsyncDieselConnectionManager::new(DB_URL))
-        .await
-        .map_err(io::Error::other)
-        .map(|pool| Pool {
+impl Pool {
+    pub async fn create() -> HandleResult<Self> {
+        let pool = bb8::Pool::builder()
+            .max_size(1)
+            .min_idle(Some(1))
+            .test_on_check_out(false)
+            .build(AsyncDieselConnectionManager::new(DB_URL))
+            .await?;
+
+        Ok(Self {
             pool,
             pool,
-            rng: RefCell::new(Rand::default()),
+            rng: Default::default(),
         })
         })
-}
+    }
 
 
-impl Pool {
     pub async fn get_world(&self) -> HandleResult<World> {
     pub async fn get_world(&self) -> HandleResult<World> {
         {
         {
-            use crate::schema::world::dsl::*;
+            use schema::world::dsl::*;
 
 
             let w_id = self.rng.borrow_mut().gen_id();
             let w_id = self.rng.borrow_mut().gen_id();
             let mut conn = self.pool.get().await?;
             let mut conn = self.pool.get().await?;
@@ -52,57 +43,58 @@ impl Pool {
     }
     }
 
 
     pub async fn get_worlds(&self, num: u16) -> HandleResult<Vec<World>> {
     pub async fn get_worlds(&self, num: u16) -> HandleResult<Vec<World>> {
-        try_join_all({
-            use crate::schema::world::dsl::*;
+        {
+            use schema::world::dsl::*;
 
 
             let mut conn = self.pool.get().await?;
             let mut conn = self.pool.get().await?;
-            let mut rng = self.rng.borrow_mut();
-
-            core::iter::repeat_with(|| {
-                let w_id = rng.gen_id();
-                world.filter(id.eq(w_id)).first(&mut conn).map_err(Into::into)
-            })
-            .take(num as _)
-            .collect::<Vec<_>>()
-        })
+            self.rng
+                .borrow_mut()
+                .gen_multi()
+                .take(num as _)
+                .map(|w_id| world.filter(id.eq(w_id)).first(&mut conn).map_err(Into::into))
+                .collect::<TryJoinAll<_>>()
+        }
         .await
         .await
     }
     }
 
 
     pub async fn update(&self, num: u16) -> HandleResult<Vec<World>> {
     pub async fn update(&self, num: u16) -> HandleResult<Vec<World>> {
-        let (get, update) = {
-            use crate::schema::world::dsl::*;
+        {
+            use schema::world::dsl::*;
 
 
             let mut conn = self.pool.get().await?;
             let mut conn = self.pool.get().await?;
             let mut rng = self.rng.borrow_mut();
             let mut rng = self.rng.borrow_mut();
-
-            let (rngs, get) = core::iter::repeat_with(|| {
-                let w_id = rng.gen_id();
-                let rng = rng.gen_id();
-
-                let get = world.filter(id.eq(w_id)).first::<World>(&mut conn);
-
-                ((w_id, rng), async move {
-                    let mut w = get.await?;
-                    w.randomnumber = rng;
-                    HandleResult::Ok(w)
+            let mut params = Vec::with_capacity(num as _);
+
+            let get = rng
+                .clone()
+                .gen_multi()
+                .take(num as _)
+                .zip(rng.gen_multi())
+                .map(|(w_id, rng)| {
+                    let get = world.filter(id.eq(w_id)).first::<World>(&mut conn);
+
+                    params.push((w_id, rng));
+
+                    async move {
+                        let mut w = get.await?;
+                        w.randomnumber = rng;
+                        HandleResult::Ok(w)
+                    }
                 })
                 })
-            })
-            .take(num as _)
-            .collect::<(Vec<_>, Vec<_>)>();
-
-            let update = diesel::sql_query(update_query_from_ids(rngs))
-                .execute(&mut conn)
-                .map_err(Into::into);
+                .collect::<TryJoinAll<_>>();
 
 
-            (try_join_all(get), update)
-        };
+            let sql = update_query_from_ids(params);
+            let update = diesel::sql_query(sql).execute(&mut conn).map_err(Into::into);
 
 
-        try_join(get, update).await.map(|(worlds, _)| worlds)
+            try_join(get, update)
+        }
+        .await
+        .map(|(worlds, _)| worlds)
     }
     }
 
 
     pub async fn tell_fortune(&self) -> HandleResult<Fortunes> {
     pub async fn tell_fortune(&self) -> HandleResult<Fortunes> {
         {
         {
-            use crate::schema::fortune::dsl::*;
+            use schema::fortune::dsl::*;
 
 
             let mut conn = self.pool.get().await?;
             let mut conn = self.pool.get().await?;
             fortune.load(&mut conn).map_err(Into::into)
             fortune.load(&mut conn).map_err(Into::into)
@@ -111,3 +103,43 @@ impl Pool {
         .map(Fortunes::new)
         .map(Fortunes::new)
     }
     }
 }
 }
+
+mod schema {
+    diesel::table! {
+        world (id) {
+            id -> Integer,
+            randomnumber -> Integer,
+        }
+    }
+
+    diesel::table! {
+        fortune (id) {
+            id -> Integer,
+            message -> Text,
+        }
+    }
+}
+
+// diesel does not support high level bulk update api. use raw sql to bypass the limitation.
+// relate discussion: https://github.com/diesel-rs/diesel/discussions/2879
+fn update_query_from_ids(mut rngs: Vec<(i32, i32)>) -> String {
+    rngs.sort_by(|(a, _), (b, _)| a.cmp(b));
+
+    const PREFIX: &str = "UPDATE world SET randomNumber=w.r FROM (VALUES ";
+    const SUFFIX: &str = ") AS w (i,r) WHERE world.id=w.i";
+
+    let mut query = String::from(PREFIX);
+
+    use core::fmt::Write;
+    rngs.iter().for_each(|(w_id, num)| {
+        write!(query, "({}::int,{}::int),", w_id, num).unwrap();
+    });
+
+    if query.ends_with(',') {
+        query.pop();
+    }
+
+    query.push_str(SUFFIX);
+
+    query
+}

+ 27 - 66
frameworks/Rust/xitca-web/src/db_toasty.rs

@@ -1,9 +1,5 @@
-use core::cell::RefCell;
-
-use std::io;
-
+use futures_util::future::try_join_all;
 use toasty::Db;
 use toasty::Db;
-use xitca_postgres_toasty::PostgreSQL;
 
 
 use crate::{
 use crate::{
     ser::{Fortune, Fortunes, World},
     ser::{Fortune, Fortunes, World},
@@ -13,85 +9,50 @@ use crate::{
 // this is not a realistic connection pool.
 // this is not a realistic connection pool.
 pub struct Pool {
 pub struct Pool {
     db: Db,
     db: Db,
-    rng: RefCell<Rand>,
-}
-
-pub async fn create() -> io::Result<Pool> {
-    let conn = PostgreSQL::connect(DB_URL).await.unwrap();
-
-    let db = Db::builder()
-        .register::<World>()
-        .register::<Fortune>()
-        .build(conn)
-        .await
-        .unwrap();
-
-    Ok(Pool {
-        db,
-        rng: Default::default(),
-    })
+    rng: core::cell::RefCell<Rand>,
 }
 }
 
 
 impl Pool {
 impl Pool {
+    pub async fn create() -> HandleResult<Self> {
+        let conn = xitca_postgres_toasty::PostgreSQL::connect(DB_URL).await?;
+
+        let db = Db::builder()
+            .register::<World>()
+            .register::<Fortune>()
+            .build(conn)
+            .await?;
+
+        Ok(Self {
+            db,
+            rng: Default::default(),
+        })
+    }
+
     pub async fn get_world(&self) -> HandleResult<World> {
     pub async fn get_world(&self) -> HandleResult<World> {
         let id = self.rng.borrow_mut().gen_id();
         let id = self.rng.borrow_mut().gen_id();
         World::get_by_id(&self.db, id).await.map_err(Into::into)
         World::get_by_id(&self.db, id).await.map_err(Into::into)
     }
     }
 
 
     pub async fn get_worlds(&self, num: u16) -> HandleResult<Vec<World>> {
     pub async fn get_worlds(&self, num: u16) -> HandleResult<Vec<World>> {
-        let res = {
-            let mut rng = self.rng.borrow_mut();
-            core::iter::repeat_with(|| {
-                let id = rng.gen_id();
-                World::get_by_id(&self.db, id)
-            })
-            .take(num as _)
-            .collect::<Vec<_>>()
-        };
-
-        let mut worlds = Vec::with_capacity(num as _);
-
-        for fut in res {
-            let world = fut.await?;
-            worlds.push(world);
-        }
-
-        Ok(worlds)
+        try_join_all(core::iter::repeat_with(|| self.get_world()).take(num as _)).await
     }
     }
 
 
     pub async fn update(&self, num: u16) -> HandleResult<Vec<World>> {
     pub async fn update(&self, num: u16) -> HandleResult<Vec<World>> {
-        let res = {
-            let mut rng = self.rng.borrow_mut();
+        let mut worlds = self.get_worlds(num).await?;
 
 
-            core::iter::repeat_with(|| {
-                let id = rng.gen_id();
-                let rng = rng.gen_id();
-
-                let fut = World::get_by_id(&self.db, id);
-                async move {
-                    let mut world = fut.await?;
-                    world.randomnumber = rng;
-                    HandleResult::Ok(world)
-                }
-            })
-            .take(num as _)
-            .collect::<Vec<_>>()
-        };
-
-        let mut worlds = Vec::with_capacity(num as _);
-
-        for fut in res {
-            let mut world = fut.await?;
-            let rng = world.randomnumber;
-            world.update().randomnumber(rng).exec(&self.db).await?;
-            worlds.push(world);
-        }
+        try_join_all({
+            let mut rng = self.rng.borrow_mut();
+            worlds
+                .iter_mut()
+                .map(move |world| world.update().randomnumber(rng.gen_id()).exec(&self.db))
+        })
+        .await?;
 
 
         Ok(worlds)
         Ok(worlds)
     }
     }
 
 
     pub async fn tell_fortune(&self) -> HandleResult<Fortunes> {
     pub async fn tell_fortune(&self) -> HandleResult<Fortunes> {
-        let mut fortunes = Fortune::all().all(&self.db).await?.collect::<Vec<_>>().await?;
+        let fortunes = Fortune::all().all(&self.db).await?.collect().await?;
         Ok(Fortunes::new(fortunes))
         Ok(Fortunes::new(fortunes))
     }
     }
 }
 }

+ 22 - 24
frameworks/Rust/xitca-web/src/db_unrealistic.rs

@@ -26,10 +26,10 @@ pub struct Client {
 pub async fn create() -> HandleResult<Client> {
 pub async fn create() -> HandleResult<Client> {
     let (cli, mut drv) = xitca_postgres::Postgres::new(DB_URL).connect().await?;
     let (cli, mut drv) = xitca_postgres::Postgres::new(DB_URL).connect().await?;
 
 
-    tokio::task::spawn(tokio::task::unconstrained(async move {
+    tokio::task::spawn(async move {
         while drv.try_next().await?.is_some() {}
         while drv.try_next().await?.is_some() {}
         HandleResult::Ok(())
         HandleResult::Ok(())
-    }));
+    });
 
 
     let world = WORLD_STMT.execute(&cli).await?.leak();
     let world = WORLD_STMT.execute(&cli).await?.leak();
     let fortune = FORTUNE_STMT.execute(&cli).await?.leak();
     let fortune = FORTUNE_STMT.execute(&cli).await?.leak();
@@ -53,16 +53,16 @@ impl Client {
     }
     }
 
 
     pub async fn get_worlds(&self, num: u16) -> HandleResult<Vec<World>> {
     pub async fn get_worlds(&self, num: u16) -> HandleResult<Vec<World>> {
-        let len = num as usize;
-
         let mut res = {
         let mut res = {
             let (ref mut rng, ref mut buf) = *self.shared.borrow_mut();
             let (ref mut rng, ref mut buf) = *self.shared.borrow_mut();
-            let mut pipe = Pipeline::with_capacity_from_buf(len, buf);
-            (0..num).try_for_each(|_| self.world.bind([rng.gen_id()]).query(&mut pipe))?;
+            let mut pipe = Pipeline::with_capacity_from_buf(num as _, buf);
+            rng.gen_multi()
+                .take(num as _)
+                .try_for_each(|id| self.world.bind([id]).query(&mut pipe))?;
             pipe.query(&self.cli)?
             pipe.query(&self.cli)?
         };
         };
 
 
-        let mut worlds = Vec::with_capacity(len);
+        let mut worlds = Vec::with_capacity(num as _);
 
 
         while let Some(mut item) = res.try_next().await? {
         while let Some(mut item) = res.try_next().await? {
             while let Some(row) = item.try_next().await? {
             while let Some(row) = item.try_next().await? {
@@ -78,23 +78,21 @@ impl Client {
 
 
         let (mut res, worlds) = {
         let (mut res, worlds) = {
             let (ref mut rng, ref mut buf) = *self.shared.borrow_mut();
             let (ref mut rng, ref mut buf) = *self.shared.borrow_mut();
-            // unrealistic as all queries are sent with only one sync point.
-            let mut pipe = Pipeline::unsync_with_capacity_from_buf(len + 1, buf);
-
-            let (mut params, worlds) = core::iter::repeat_with(|| {
-                let id = rng.gen_id();
-                let rand = rng.gen_id();
-                self.world.bind([id]).query(&mut pipe)?;
-                HandleResult::Ok(((id, rand), World::new(id, rand)))
-            })
-            .take(len)
-            .collect::<Result<(Vec<_>, Vec<_>), _>>()?;
-
-            params.sort();
-
-            params
-                .into_iter()
-                .try_for_each(|(id, rng)| self.update.bind([rng, id]).query(&mut pipe))?;
+            let mut pipe = Pipeline::with_capacity_from_buf(len + 1, buf);
+
+            let mut ids = rng.gen_multi().take(num as _).collect::<Vec<_>>();
+            ids.sort();
+
+            let (rngs, worlds) = ids
+                .iter()
+                .cloned()
+                .zip(rng.gen_multi())
+                .map(|(id, rand)| {
+                    self.world.bind([id]).query(&mut pipe)?;
+                    HandleResult::Ok((rand, World::new(id, rand)))
+                })
+                .collect::<HandleResult<(Vec<_>, Vec<_>)>>()?;
+            self.update.bind([&ids, &rngs]).query(&mut pipe)?;
 
 
             (pipe.query(&self.cli)?, worlds)
             (pipe.query(&self.cli)?, worlds)
         };
         };

+ 0 - 29
frameworks/Rust/xitca-web/src/db_util.rs

@@ -1,28 +1,3 @@
-#[cfg(feature = "diesel")]
-// diesel does not support high level bulk update api. use raw sql to bypass the limitation.
-// relate discussion: https://github.com/diesel-rs/diesel/discussions/2879
-pub fn update_query_from_ids(mut rngs: Vec<(i32, i32)>) -> String {
-    rngs.sort_by(|(a, _), (b, _)| a.cmp(b));
-
-    const PREFIX: &str = "UPDATE world SET randomNumber=w.r FROM (VALUES ";
-    const SUFFIX: &str = ") AS w (i,r) WHERE world.id=w.i";
-
-    let mut query = String::from(PREFIX);
-
-    use core::fmt::Write;
-    rngs.iter().for_each(|(w_id, num)| {
-        write!(query, "({}::int,{}::int),", w_id, num).unwrap();
-    });
-
-    if query.ends_with(',') {
-        query.pop();
-    }
-
-    query.push_str(SUFFIX);
-
-    query
-}
-
 #[cfg(feature = "pg")]
 #[cfg(feature = "pg")]
 pub use pg::*;
 pub use pg::*;
 
 
@@ -44,10 +19,6 @@ pub mod pg {
     pub const WORLD_STMT: StatementNamed =
     pub const WORLD_STMT: StatementNamed =
         Statement::named("SELECT id,randomnumber FROM world WHERE id=$1", &[Type::INT4]);
         Statement::named("SELECT id,randomnumber FROM world WHERE id=$1", &[Type::INT4]);
     pub const UPDATE_STMT: StatementNamed = Statement::named(
     pub const UPDATE_STMT: StatementNamed = Statement::named(
-        "UPDATE world SET randomnumber=$1 WHERE id=$2",
-        &[Type::INT4, Type::INT4],
-    );
-    pub const UPDATE_BATCH_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",
         "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],
         &[Type::INT4_ARRAY, Type::INT4_ARRAY],
     );
     );

+ 8 - 11
frameworks/Rust/xitca-web/src/main_orm.rs

@@ -1,13 +1,13 @@
 mod ser;
 mod ser;
 mod util;
 mod util;
 
 
-#[cfg(feature = "diesel")]
-mod db_diesel;
-#[cfg(feature = "diesel")]
-mod schema;
+#[cfg(all(feature = "diesel", not(feature = "toasty")))]
+#[path = "./db_diesel.rs"]
+mod orm;
 
 
-#[cfg(feature = "toasty")]
-mod db_toasty;
+#[cfg(all(feature = "toasty", not(feature = "diesel")))]
+#[path = "./db_toasty.rs"]
+mod orm;
 
 
 use ser::{Num, World};
 use ser::{Num, World};
 use util::{HandleResult, SERVER_HEADER_VALUE};
 use util::{HandleResult, SERVER_HEADER_VALUE};
@@ -18,14 +18,11 @@ use xitca_web::{
     http::{WebResponse, header::SERVER},
     http::{WebResponse, header::SERVER},
 };
 };
 
 
-#[cfg(feature = "diesel")]
-use db_diesel::{Pool, create};
-#[cfg(feature = "toasty")]
-use db_toasty::{Pool, create};
+use orm::Pool;
 
 
 fn main() -> std::io::Result<()> {
 fn main() -> std::io::Result<()> {
     App::new()
     App::new()
-        .with_async_state(create)
+        .with_async_state(Pool::create)
         .at_typed(db)
         .at_typed(db)
         .at_typed(fortunes)
         .at_typed(fortunes)
         .at_typed(queries)
         .at_typed(queries)

+ 0 - 13
frameworks/Rust/xitca-web/src/schema.rs

@@ -1,13 +0,0 @@
-diesel::table! {
-    world (id) {
-        id -> Integer,
-        randomnumber -> Integer,
-    }
-}
-
-diesel::table! {
-    fortune (id) {
-        id -> Integer,
-        message -> Text,
-    }
-}

+ 14 - 5
frameworks/Rust/xitca-web/src/util.rs

@@ -1,7 +1,6 @@
 #![allow(dead_code)]
 #![allow(dead_code)]
 
 
-use core::cell::RefCell;
-
+use rand::{Rng, SeedableRng, distr::Uniform, rngs::SmallRng};
 use xitca_http::{bytes::BytesMut, http::header::HeaderValue};
 use xitca_http::{bytes::BytesMut, http::header::HeaderValue};
 
 
 pub trait QueryParse {
 pub trait QueryParse {
@@ -33,7 +32,7 @@ pub const DB_URL: &str = "postgres://benchmarkdbuser:benchmarkdbpass@tfb-databas
 
 
 pub struct State<DB> {
 pub struct State<DB> {
     pub client: DB,
     pub client: DB,
-    pub write_buf: RefCell<BytesMut>,
+    pub write_buf: core::cell::RefCell<BytesMut>,
 }
 }
 
 
 impl<DB> State<DB> {
 impl<DB> State<DB> {
@@ -45,8 +44,6 @@ impl<DB> State<DB> {
     }
     }
 }
 }
 
 
-use rand::{Rng, SeedableRng, rngs::SmallRng};
-
 pub struct Rand(SmallRng);
 pub struct Rand(SmallRng);
 
 
 impl Default for Rand {
 impl Default for Rand {
@@ -55,9 +52,21 @@ impl Default for Rand {
     }
     }
 }
 }
 
 
+impl Clone for Rand {
+    #[inline]
+    fn clone(&self) -> Self {
+        Self(self.0.clone())
+    }
+}
+
 impl Rand {
 impl Rand {
     #[inline]
     #[inline]
     pub fn gen_id(&mut self) -> i32 {
     pub fn gen_id(&mut self) -> i32 {
         self.0.random_range(1..=10000)
         self.0.random_range(1..=10000)
     }
     }
+
+    #[inline]
+    pub fn gen_multi(&mut self) -> impl Iterator<Item = i32> {
+        (&mut self.0).sample_iter(Uniform::new(1, 10001).unwrap())
+    }
 }
 }