Bläddra i källkod

Merge pull request #32 from TechEmpower/master

aa
三刀 1 år sedan
förälder
incheckning
a5f20650de
51 ändrade filer med 1259 tillägg och 288 borttagningar
  1. 38 0
      frameworks/C++/just-boost/README.md
  2. 27 0
      frameworks/C++/just-boost/benchmark_config.json
  3. 25 0
      frameworks/C++/just-boost/just-boost.dockerfile
  4. 396 0
      frameworks/C++/just-boost/main.cpp
  5. 1 1
      frameworks/C++/userver/userver-bare.dockerfile
  6. 1 1
      frameworks/C++/userver/userver.dockerfile
  7. 7 0
      frameworks/C++/userver/userver_benchmark/common/db_helpers.cpp
  8. 7 2
      frameworks/C++/userver/userver_benchmark/common/db_helpers.hpp
  9. 8 7
      frameworks/C++/userver/userver_benchmark/controllers/fortunes/handler.cpp
  10. 1 1
      frameworks/C++/userver/userver_benchmark/controllers/updates/handler.cpp
  11. 4 3
      frameworks/C++/userver/userver_configs/static_config.yaml
  12. 4 4
      frameworks/C/h2o/h2o.dockerfile
  13. 4 4
      frameworks/C/h2o/src/database.c
  14. 30 17
      frameworks/C/h2o/src/handlers/world.c
  15. 1 0
      frameworks/CSharp/aspnetcore/aspnetcore.dockerfile
  16. 1 2
      frameworks/FSharp/giraffe/README.md
  17. 0 18
      frameworks/FSharp/giraffe/benchmark_config.json
  18. 0 12
      frameworks/FSharp/giraffe/config.toml
  19. 4 4
      frameworks/FSharp/giraffe/giraffe-newtonsoft.dockerfile
  20. 0 19
      frameworks/FSharp/giraffe/giraffe-utf8json.dockerfile
  21. 4 4
      frameworks/FSharp/giraffe/giraffe.dockerfile
  22. 5 8
      frameworks/FSharp/giraffe/src/App/App.fsproj
  23. 3 8
      frameworks/FSharp/giraffe/src/App/Program.fs
  24. 1 1
      frameworks/FSharp/zebra/README.md
  25. 4 6
      frameworks/FSharp/zebra/src/App/App.fsproj
  26. 4 4
      frameworks/FSharp/zebra/zebra-simple.dockerfile
  27. 4 4
      frameworks/FSharp/zebra/zebra.dockerfile
  28. 6 5
      frameworks/JavaScript/nodejs/app.js
  29. 1 1
      frameworks/JavaScript/nodejs/create-server.js
  30. 6 6
      frameworks/JavaScript/nodejs/handlers/postgres.js
  31. 11 12
      frameworks/Kotlin/http4k/core-pgclient/src/main/kotlin/PostgresDatabase.kt
  32. 1 1
      frameworks/Python/aiohttp/requirements.txt
  33. 1 1
      frameworks/Python/api_hour/requirements.txt
  34. 1 1
      frameworks/Ruby/hanami/config/auto_tune.rb
  35. 1 1
      frameworks/Ruby/rack/config/auto_tune.rb
  36. 1 1
      frameworks/Ruby/rails/config/database.yml
  37. 1 1
      frameworks/Rust/gotham/gotham.dockerfile
  38. 1 1
      frameworks/Rust/ntex/src/main.rs
  39. 1 1
      frameworks/Rust/ntex/src/main_db.rs
  40. 1 1
      frameworks/Rust/ntex/src/main_plt.rs
  41. 352 55
      frameworks/Rust/xitca-web/Cargo.lock
  42. 23 9
      frameworks/Rust/xitca-web/Cargo.toml
  43. 18 0
      frameworks/Rust/xitca-web/benchmark_config.json
  44. 1 1
      frameworks/Rust/xitca-web/rust-toolchain.toml
  45. 16 23
      frameworks/Rust/xitca-web/src/main.rs
  46. 189 0
      frameworks/Rust/xitca-web/src/main_axum.rs
  47. 10 11
      frameworks/Rust/xitca-web/src/main_iou.rs
  48. 15 19
      frameworks/Rust/xitca-web/src/main_wasm.rs
  49. 2 0
      frameworks/Rust/xitca-web/src/util.rs
  50. 10 0
      frameworks/Rust/xitca-web/xitca-web-axum.dockerfile
  51. 6 7
      frameworks/Rust/xitca-web/xitca-web-wasm.dockerfile

+ 38 - 0
frameworks/C++/just-boost/README.md

@@ -0,0 +1,38 @@
+# Just.Boost Benchmarking Test
+
+## Description
+
+Backend using just C++(20) and Boost.
+
+## Run Test
+
+    cd FrameworkBenchmarks/
+    ./tfb --mode verify --test just-boost
+
+## Software Versions
+
+- [Alpine 3.18](https://hub.docker.com/_/alpine)
+- [gcc](https://gcc.gnu.org/)
+- [c++20](https://en.cppreference.com/w/cpp/20)
+- [Boost](https://www.boost.org/)
+	- [Beast](https://www.boost.org/doc/libs/1_83_0/libs/beast/doc/html/index.html) ([HTTP Server with C++ 20 coroutine](https://www.boost.org/doc/libs/1_83_0/libs/beast/example/http/server/awaitable/http_server_awaitable.cpp))
+	- [JSON](https://www.boost.org/doc/libs/1_83_0/libs/json/doc/html/index.html)
+- [libpq — C Library](https://www.postgresql.org/docs/current/libpq.html) (PostgreSQL client)
+
+## Test URLs
+
+### Test 1: JSON Encoding
+
+    http://localhost:8000/json
+
+### Test 2: Single Row Query
+
+    http://localhost:8000/db
+
+### Test 3: Multi Row Query
+
+    http://localhost:8000/queries/{count}
+
+### Test 6: Plaintext
+
+    http://localhost:8000/plaintext

+ 27 - 0
frameworks/C++/just-boost/benchmark_config.json

@@ -0,0 +1,27 @@
+{
+  "framework": "just-boost",
+  "tests": [
+    {
+      "default": {
+        "json_url": "/json",
+        "plaintext_url": "/plaintext",
+        "db_url": "/db",
+        "query_url": "/queries/",
+        "port": 8000,
+        "approach": "Realistic",
+        "classification": "Micro",
+        "database": "Postgres",
+        "framework": "Boost",
+        "language": "C++",
+        "orm": "Raw",
+        "platform": "None",
+        "webserver": "None",
+        "os": "Linux",
+        "database_os": "Linux",
+        "display_name": "just-boost",
+        "notes": "",
+        "versus": ""
+      }
+    }
+  ]
+}

+ 25 - 0
frameworks/C++/just-boost/just-boost.dockerfile

@@ -0,0 +1,25 @@
+# docker build --progress=plain --build-arg CXXFLAGS="-Wall" -t just-boost -f just-boost.dockerfile .
+# docker run --rm --name just-boost -p 8000:8000 -d just-boost
+# docker container stop just-boost
+FROM alpine:3.18
+
+ARG APP=just-boost
+ARG CXXFLAGS=-O3
+
+ENV LANG=C.UTF-8 LC_ALL=C.UTF-8
+ENV BCPP_PG_CONN_STR="postgres://benchmarkdbuser:benchmarkdbpass@tfb-database/hello_world"
+ENV BCPP_N_THREADS=32
+
+WORKDIR /usr/src/${APP}
+
+RUN apk add --no-cache build-base boost-dev libpq-dev
+COPY *.cpp ./
+RUN g++ ${CXXFLAGS} -std=c++20 \
+        -I$(pg_config --includedir) \
+        -o main main.cpp \
+        -L$(pg_config --libdir) -lpq \
+        && rm *.cpp
+
+EXPOSE 8000
+
+CMD ["./main"]

+ 396 - 0
frameworks/C++/just-boost/main.cpp

@@ -0,0 +1,396 @@
+#include <boost/beast/core.hpp>
+#include <boost/beast/http.hpp>
+#include <boost/beast/version.hpp>
+#include <boost/asio/ip/tcp.hpp>
+#include <boost/asio/awaitable.hpp>
+#include <boost/asio/co_spawn.hpp>
+#include <boost/asio/use_awaitable.hpp>
+#include <boost/config.hpp>
+#include <boost/json/src.hpp>
+
+#include <algorithm>
+#include <cstdlib>
+#include <ctime>
+#include <iostream>
+#include <memory>
+#include <string>
+#include <thread>
+#include <vector>
+#include <random>
+
+#if defined(BOOST_ASIO_HAS_CO_AWAIT)
+
+#include <libpq-fe.h>
+
+namespace beast = boost::beast;   // from <boost/beast.hpp>
+namespace http = beast::http;     // from <boost/beast/http.hpp>
+namespace net = boost::asio;      // from <boost/asio.hpp>
+using tcp = boost::asio::ip::tcp; // from <boost/asio/ip/tcp.hpp>
+namespace json = boost::json;     // from <boost/json.hpp>
+
+using tcp_stream = typename beast::tcp_stream::rebind_executor<
+		net::use_awaitable_t<>::executor_with_default<net::any_io_executor>>::other;
+
+namespace becpp
+{
+
+using result_ptr = std::unique_ptr<PGresult, decltype(&PQclear)>;
+
+//https://gist.github.com/ictlyh/12fe787ec265b33fd7e4b0bd08bc27cb
+result_ptr prepare(PGconn* conn,
+                   const char* stmtName,
+                   const char* command,
+                   uint8_t nParams)
+{
+	auto res = PQprepare(conn, stmtName, command, nParams, nullptr);
+	if (PQresultStatus(res) != PGRES_COMMAND_OK)
+	{
+		std::cerr << "PQprepare failed: " << PQresultErrorMessage(res)
+			        << std::endl;
+		PQclear(res);
+		return {nullptr, nullptr};
+	}
+
+	return {res, &PQclear};
+}
+
+result_ptr execute(PGconn* conn,
+                   const char* stmtName,
+                   uint8_t nParams,
+                   const char* const* paramValues,
+                   const int* paramLengths = nullptr,
+                   const int* paramFormats = nullptr,
+                   int resultFormat = 0)
+{
+	auto res = PQexecPrepared(conn, stmtName, nParams, paramValues, paramLengths,
+	                          paramFormats, resultFormat);
+	const auto status = PQresultStatus(res);
+	if (status != PGRES_COMMAND_OK &&
+	    status != PGRES_TUPLES_OK  &&
+	    status != PGRES_SINGLE_TUPLE)
+	{
+		std::cerr << "PQexecPrepared failed: " << PQresultErrorMessage(res)
+		          << std::endl;
+		PQclear(res);
+		return {nullptr, nullptr};
+	}
+
+	return {res, &PQclear};
+}
+
+const char* env(const char* env_var, const char* default_value)
+{
+	if (const char* env_p = std::getenv(env_var))
+		return env_p;
+
+	return default_value;
+}
+
+std::string now_string()
+{
+	std::time_t time = std::time(nullptr);
+	char timeString[std::size("Wed, 17 Apr 2013 12:00:00 GMT")];
+	std::strftime(std::data(timeString), std::size(timeString), "%a, %d %b %Y %X %Z", std::localtime(&time));
+	return timeString;
+}
+
+template <class Body, class Allocator>
+http::message_generator
+handle_error(
+	http::request<Body, http::basic_fields<Allocator>>&& req,
+	http::status status,
+	beast::string_view msg)
+{
+	http::response<http::string_body> res{status, req.version()};
+	res.set(http::field::server, BOOST_BEAST_VERSION_STRING);
+	res.set(http::field::content_type, "text/html");
+	res.set(http::field::date, now_string());
+	res.keep_alive(req.keep_alive());
+	res.body() = std::string(msg);
+	res.prepare_payload();
+	return res;
+}
+
+template <class Body, class Allocator>
+http::message_generator
+handle_target(
+	http::request<Body, http::basic_fields<Allocator>>&& req,
+	PGconn* conn = nullptr)
+{
+	static std::string msg = "Hello, World!";
+
+	//std::cout << "handle_target: " << req.target() << std::endl;
+	http::response<http::string_body> res{http::status::ok, req.version()};
+	res.set(http::field::server, BOOST_BEAST_VERSION_STRING);
+	res.set(http::field::content_type, "application/json");
+	res.set(http::field::date, now_string());
+	res.keep_alive(req.keep_alive());
+	
+	if (req.target() == "/json")
+	{
+		// {"message":"Hello, World!"}
+		json::object obj;
+		obj["message"] = msg;
+		res.body() = json::serialize(obj);
+	}
+	else if (req.target() == "/plaintext")
+	{
+		res.set(http::field::content_type, "text/plain");
+		res.body() = msg;
+	}
+	else if (req.target() == "/db" || req.target().starts_with("/queries/"))
+	{
+		static std::random_device rd;
+		static std::minstd_rand gen(rd());
+		static std::uniform_int_distribution<> distrib(1, 10000);
+		static const char* word_query = "SELECT randomNumber FROM world WHERE id=$1";
+		thread_local auto stmt = prepare(conn, "word_query_stmt", word_query, 1);
+
+		if (req.target() == "/db")
+		{
+			const unsigned uint_id = distrib(gen);
+			const auto str_id =  std::to_string(uint_id);
+			const char* char_ptr_id = str_id.c_str();
+			if (auto rs = execute(conn, "word_query_stmt", 1, &char_ptr_id))
+			{
+				// {"id":3217,"randomNumber":2149}
+				json::object obj;
+				obj["id"] = uint_id;
+				obj["randomNumber"] = std::atoi(PQgetvalue(rs.get(), 0, 0));
+				res.body() = json::serialize(obj);
+				//std::cout << "res.body(): " << res.body() << std::endl;
+			}
+			else
+				return handle_error(std::move(req),
+				                    http::status::internal_server_error,
+				                    "internal_server_error");
+		}
+		else if (req.target().starts_with("/queries/"))
+		{
+			int n_queries = 1;
+			try
+			{
+				const int n = std::stoi(req.target().substr(req.target().find_last_of('/')+1));
+				if (n > 1) n_queries = n;
+			} catch(...) {}
+			if (n_queries > 500) n_queries = 500;
+			json::array objs;
+			for (auto i = 0; i < n_queries; ++i)
+			{
+				const unsigned uint_id = distrib(gen);
+				const auto str_id =  std::to_string(uint_id);
+				const char* char_ptr_id = str_id.c_str();
+				if (auto rs = execute(conn, "word_query_stmt", 1, &char_ptr_id))
+				{
+					// {"id":3217,"randomNumber":2149}
+					json::object obj;
+					obj["id"] = uint_id;
+					obj["randomNumber"] = std::atoi(PQgetvalue(rs.get(), 0, 0));
+					objs.push_back(obj);
+				}
+				else
+					return handle_error(std::move(req),
+					                    http::status::internal_server_error,
+					                    "internal_server_error");
+			}
+			res.body() = json::serialize(objs);
+			//std::cout << "res.body(): " << res.body() << std::endl;
+		}
+	}
+	else
+	{
+		return handle_error(std::move(req),
+		                    http::status::not_found,
+		                    "Unhandled target: '" + std::string(req.target()) + "'");
+	}
+
+	res.prepare_payload();
+	return res;
+}
+
+// Return a response for the given request.
+//
+// The concrete type of the response message (which depends on the
+// request), is type-erased in message_generator.
+template <class Body, class Allocator>
+http::message_generator
+handle_request(
+	http::request<Body, http::basic_fields<Allocator>>&& req)
+{
+	// Make sure we can handle the method
+	if (req.method() != http::verb::get)
+		return handle_error(std::move(req),
+		                    http::status::not_found,
+		                    "Unhandled method: '" + std::string(req.method_string()) + "'");
+
+	if (req.target() == "/json" || req.target() == "/plaintext")
+		return handle_target(std::move(req));
+
+	thread_local std::unique_ptr<PGconn, decltype(&PQfinish)> conn
+	{
+		PQconnectdb(env("BCPP_PG_CONN_STR", "")),
+		&PQfinish
+	};
+	if (PQstatus(conn.get()) != CONNECTION_OK)
+	{
+		auto msg = PQerrorMessage(conn.get());
+		std::cerr << "PQerrorMessage: " << msg << std::endl;
+		return handle_error(std::move(req),
+		                    http::status::internal_server_error,
+		                    msg);
+	}
+	return handle_target(std::move(req), conn.get());
+}
+
+}
+//------------------------------------------------------------------------------
+
+
+// Handles an HTTP server connection
+net::awaitable<void>
+do_session(tcp_stream stream)
+{
+	// This buffer is required to persist across reads
+	beast::flat_buffer buffer;
+
+	// This lambda is used to send messages
+	try
+	{
+		for(;;)
+		{
+			// Set the timeout.
+			stream.expires_after(std::chrono::seconds(30));
+
+			// Read a request
+			http::request<http::string_body> req;
+			co_await http::async_read(stream, buffer, req);
+
+			// Handle the request
+			http::message_generator msg =
+				becpp::handle_request(std::move(req));
+
+			// Determine if we should close the connection
+			bool keep_alive = msg.keep_alive();
+
+			// Send the response
+			co_await beast::async_write(stream, std::move(msg), net::use_awaitable);
+
+			if(! keep_alive)
+			{
+				// This means we should close the connection, usually because
+				// the response indicated the "Connection: close" semantic.
+				break;
+			}
+		}
+	}
+	catch (boost::system::system_error & se)
+	{
+		if (se.code() != http::error::end_of_stream )
+			throw ;
+	}
+
+	// Send a TCP shutdown
+	beast::error_code ec;
+	stream.socket().shutdown(tcp::socket::shutdown_send, ec);
+
+	// At this point the connection is closed gracefully
+	// we ignore the error because the client might have
+	// dropped the connection already.
+}
+
+//------------------------------------------------------------------------------
+
+// Accepts incoming connections and launches the sessions
+net::awaitable<void>
+do_listen(tcp::endpoint endpoint)
+{
+	// Open the acceptor
+	auto acceptor = net::use_awaitable.as_default_on(tcp::acceptor(co_await net::this_coro::executor));
+	acceptor.open(endpoint.protocol());
+
+	// Allow address reuse
+	acceptor.set_option(net::socket_base::reuse_address(true));
+
+	// Bind to the server address
+	acceptor.bind(endpoint);
+
+	// Start listening for connections
+	acceptor.listen(net::socket_base::max_listen_connections);
+
+	for(;;)
+		boost::asio::co_spawn(
+			acceptor.get_executor(),
+				do_session(tcp_stream(co_await acceptor.async_accept())),
+				[](std::exception_ptr e)
+				{
+					if (e)
+						try
+						{
+							std::rethrow_exception(e);
+						}
+						catch (std::exception &e) {
+							std::cerr << "Error in session: " << e.what() << "\n";
+						}
+				});
+
+}
+
+int main(int argc, char* argv[])
+{
+	auto const address = net::ip::make_address(becpp::env("BCPP_ADDRESS", "0.0.0.0"));
+	auto const port = static_cast<unsigned short>(std::atoi(becpp::env("BCPP_PORT", "8000")));
+	auto const threads = std::max<int>(1, std::atoi(becpp::env("BCPP_N_THREADS", "3")));
+
+	std::cout << "__GNUG__=" << __GNUG__ << '\n';
+	std::cout << "__cplusplus=" << __cplusplus << '\n';
+	std::cout << "__TIMESTAMP__=" << __TIMESTAMP__ << '\n';
+	std::cout << "__GNUC_EXECUTION_CHARSET_NAME=" << __GNUC_EXECUTION_CHARSET_NAME << '\n';
+	std::cout << "Listening " << address << ':' << port << " threads=" << threads << std::endl;
+
+	// The io_context is required for all I/O
+	net::io_context ioc{threads};
+
+	// Spawn a listening port
+	boost::asio::co_spawn(ioc,
+						  do_listen(tcp::endpoint{address, port}),
+						  [](std::exception_ptr e)
+						  {
+							  if (e)
+								  try
+								  {
+									  std::rethrow_exception(e);
+								  }
+								  catch(std::exception & e)
+								  {
+									  std::cerr << "Error in acceptor: " << e.what() << "\n";
+								  }
+						  });
+
+	// Run the I/O service on the requested number of threads
+	try {
+	std::vector<std::thread> v;
+	v.reserve(threads - 1);
+	for(auto i = threads - 1; i > 0; --i)
+		v.emplace_back(
+		[&ioc]
+		{
+			ioc.run();
+		});
+	ioc.run();
+	} catch (std::exception& e)
+	{
+		std::cerr << "Error in main: " << e.what() << "\n";
+	}
+
+	return EXIT_SUCCESS;
+}
+
+#else
+
+int main(int, char * [])
+{
+	std::printf("awaitables require C++20\n");
+	return 1;
+}
+
+#endif

+ 1 - 1
frameworks/C++/userver/userver-bare.dockerfile

@@ -6,7 +6,7 @@ RUN apt update && \
 
 WORKDIR /src
 RUN git clone https://github.com/userver-framework/userver.git && \
-    cd userver && git checkout 73727ce95d24f18651fc018c45f50c492f858027
+    cd userver && git checkout 781169b63bdbc012f7d98ed045bff75ff1b0b70d
 COPY userver_benchmark/ ./
 RUN mkdir build && cd build && \
     cmake -DUSERVER_IS_THE_ROOT_PROJECT=0 -DUSERVER_FEATURE_CRYPTOPP_BLAKE2=0 \

+ 1 - 1
frameworks/C++/userver/userver.dockerfile

@@ -6,7 +6,7 @@ RUN apt update && \
 
 WORKDIR /src
 RUN git clone https://github.com/userver-framework/userver.git && \
-    cd userver && git checkout 73727ce95d24f18651fc018c45f50c492f858027
+    cd userver && git checkout 781169b63bdbc012f7d98ed045bff75ff1b0b70d
 COPY userver_benchmark/ ./
 RUN mkdir build && cd build && \
     cmake -DUSERVER_IS_THE_ROOT_PROJECT=0 -DUSERVER_FEATURE_CRYPTOPP_BLAKE2=0 \

+ 7 - 0
frameworks/C++/userver/userver_benchmark/common/db_helpers.cpp

@@ -27,6 +27,13 @@ int ParseFromQueryVal(std::string_view query_val) {
 
 }  // namespace
 
+userver::storages::postgres::Query CreateNonLoggingQuery(
+    std::string statement) {
+  return userver::storages::postgres::Query{
+      statement, std::nullopt /* name */,
+      userver::storages::postgres::Query::LogMode::kNameOnly};
+}
+
 int GenerateRandomId() {
   return userver::utils::RandRange(1, kMaxWorldRows + 1);
 }

+ 7 - 2
frameworks/C++/userver/userver_benchmark/common/db_helpers.hpp

@@ -8,11 +8,16 @@
 
 namespace userver_techempower::db_helpers {
 
+userver::storages::postgres::Query CreateNonLoggingQuery(std::string statement);
+
 constexpr int kMaxWorldRows = 10000;
-const userver::storages::postgres::Query kSelectRowQuery{
-    "SELECT id, randomNumber FROM World WHERE id = $1"};
+
+const userver::storages::postgres::Query kSelectRowQuery =
+    CreateNonLoggingQuery("SELECT id, randomNumber FROM World WHERE id = $1");
+
 constexpr auto kClusterHostType =
     userver::storages::postgres::ClusterHostType::kMaster;
+
 constexpr std::string_view kDbComponentName = "hello-world-db";
 
 struct WorldTableRow final {

+ 8 - 7
frameworks/C++/userver/userver_benchmark/controllers/fortunes/handler.cpp

@@ -14,7 +14,7 @@ const std::string kContentTypeTextHtml{"text/html; charset=utf-8"};
 
 struct Fortune final {
   int id;
-  std::string message;
+  std::string_view message;
 };
 
 constexpr std::string_view kResultingHtmlHeader{
@@ -133,7 +133,8 @@ Handler::Handler(const userver::components::ComponentConfig& config,
               .FindComponent<userver::components::Postgres>(
                   db_helpers::kDbComponentName)
               .GetCluster()},
-      select_all_fortunes_query_{"SELECT id, message FROM Fortune"},
+      select_all_fortunes_query_{
+          db_helpers::CreateNonLoggingQuery("SELECT id, message FROM Fortune")},
       semaphore_{kBestConcurrencyWildGuess} {}
 
 std::string Handler::HandleRequestThrow(
@@ -144,14 +145,14 @@ std::string Handler::HandleRequestThrow(
 }
 
 std::string Handler::GetResponse() const {
-  auto fortunes = [this] {
+  const auto pg_result = [this] {
     const auto lock = semaphore_.Acquire();
-    return pg_
-        ->Execute(db_helpers::kClusterHostType, select_all_fortunes_query_)
-        .AsContainer<std::vector<Fortune>>(
-            userver::storages::postgres::kRowTag);
+    return pg_->Execute(db_helpers::kClusterHostType,
+                        select_all_fortunes_query_);
   }();
 
+  auto fortunes = pg_result.AsContainer<std::vector<Fortune>>(
+      userver::storages::postgres::kRowTag);
   fortunes.push_back({0, "Additional fortune added at request time."});
 
   std::sort(fortunes.begin(), fortunes.end(),

+ 1 - 1
frameworks/C++/userver/userver_benchmark/controllers/updates/handler.cpp

@@ -30,7 +30,7 @@ Handler::Handler(const userver::components::ComponentConfig& config,
       pg_{context.FindComponent<userver::components::Postgres>("hello-world-db")
               .GetCluster()},
       query_arg_name_{"queries"},
-      update_query_{kUpdateQueryStr},
+      update_query_{db_helpers::CreateNonLoggingQuery(kUpdateQueryStr)},
       semaphore_{kBestConcurrencyWildGuess} {}
 
 userver::formats::json::Value Handler::HandleRequestJsonThrow(

+ 4 - 3
frameworks/C++/userver/userver_configs/static_config.yaml

@@ -17,7 +17,7 @@ components_manager:
 
         fs-task-processor:              # Make a separate task processor for filesystem bound tasks.
             thread_name: fs-worker
-            worker_threads: 4
+            worker_threads: 1
 
     default_task_processor: main-task-processor
 
@@ -49,8 +49,8 @@ components_manager:
 
         dynamic-config:                      # Dynamic config storage options, do nothing
             fs-cache-path: ''
-        dynamic-config-fallbacks:            # Load options from file and push them into the dynamic config storage.
-            fallback-path: /app/dynamic_config_fallback.json
+            defaults-path: /app/dynamic_config_fallback.json
+            fs-task-processor: fs-task-processor
 
         testsuite-support:
 
@@ -82,6 +82,7 @@ components_manager:
             max_pool_size: 260
             max_queue_size: 512
             connecting_limit: 15
+            ignore_unused_query_params: true
 
         single-query-handler:
             path: /db

+ 4 - 4
frameworks/C/h2o/h2o.dockerfile

@@ -46,7 +46,7 @@ RUN curl -LSs "https://github.com/h2o/h2o/archive/${H2O_VERSION}.tar.gz" | \
     cmake --install build && \
     cp -a deps/picotls/include/picotls* deps/quicly/include/quicly* /usr/local/include
 
-ARG MUSTACHE_C_REVISION=c1948c599edfe48c6099ed70ab1d5911d8c3ddc8
+ARG MUSTACHE_C_REVISION=7fe52392879d0188c172d94bb4fde7c513d6b929
 
 WORKDIR /tmp/mustache-c-build
 RUN curl -LSs "https://github.com/x86-64/mustache-c/archive/${MUSTACHE_C_REVISION}.tar.gz" | \
@@ -54,12 +54,12 @@ RUN curl -LSs "https://github.com/x86-64/mustache-c/archive/${MUSTACHE_C_REVISIO
     CFLAGS="-flto -march=native -mtune=native -O3" ./autogen.sh && \
     make -j "$(nproc)" install
 
-ARG POSTGRESQL_VERSION=7b7fa85130330128b404eddebd4f33c6739454b0
+ARG POSTGRESQL_VERSION=c1ec02be1d79eac95160dea7ced32ace84664617
 
 WORKDIR /tmp/postgresql-build
 RUN curl -LSs "https://github.com/postgres/postgres/archive/${POSTGRESQL_VERSION}.tar.gz" | \
       tar --strip-components=1 -xz && \
-    curl -LSs "https://www.postgresql.org/message-id/attachment/146614/v2-0001-Add-PQsendSyncMessage-to-libpq.patch" | \
+    curl -LSs "https://www.postgresql.org/message-id/attachment/152078/v5-0001-Add-PQsendPipelineSync-to-libpq.patch" | \
       patch -Np1 && \
     CFLAGS="-flto -march=native -mtune=native -O3" ./configure \
       --includedir=/usr/local/include/postgresql \
@@ -92,7 +92,7 @@ RUN apt-get -yqq update && \
 ARG H2O_APP_PREFIX
 COPY --from=compile "${H2O_APP_PREFIX}" "${H2O_APP_PREFIX}/"
 COPY --from=compile /usr/local/lib/libmustache_c.so "${H2O_APP_PREFIX}/lib/"
-COPY --from=compile /usr/local/lib/libpq.so.5.16 "${H2O_APP_PREFIX}/lib/libpq.so.5"
+COPY --from=compile /usr/local/lib/libpq.so.5.17 "${H2O_APP_PREFIX}/lib/libpq.so.5"
 ENV LD_LIBRARY_PATH="${H2O_APP_PREFIX}/lib"
 EXPOSE 8080
 ARG BENCHMARK_ENV

+ 4 - 4
frameworks/C/h2o/src/database.c

@@ -135,8 +135,8 @@ static int do_execute_query(db_conn_t *conn, db_query_param_t *param)
 		return 1;
 	}
 
-	if (!PQsendSyncMessage(conn->conn)) {
-		LIBRARY_ERROR("PQsendSyncMessage", PQerrorMessage(conn->conn));
+	if (!PQsendPipelineSync(conn->conn)) {
+		LIBRARY_ERROR("PQsendPipelineSync", PQerrorMessage(conn->conn));
 		return 1;
 	}
 
@@ -522,8 +522,8 @@ static void prepare_statements(db_conn_t *conn)
 			iter = iter->next;
 		} while (iter);
 
-		if (!PQsendSyncMessage(conn->conn)) {
-			LIBRARY_ERROR("PQsendSyncMessage", PQerrorMessage(conn->conn));
+		if (!PQsendPipelineSync(conn->conn)) {
+			LIBRARY_ERROR("PQsendPipelineSync", PQerrorMessage(conn->conn));
 			on_database_connect_error(conn, false, DB_ERROR);
 			return;
 		}

+ 30 - 17
frameworks/C/h2o/src/handlers/world.c

@@ -55,18 +55,18 @@
 #define RANDOM_NUM_KEY "randomNumber"
 
 // MAX_UPDATE_QUERY_LEN must be updated whenever UPDATE_QUERY_BEGIN, UPDATE_QUERY_ELEM,
-// and UPDATE_QUERY_END are changed.
-#define UPDATE_QUERY_BEGIN \
-	"UPDATE " WORLD_TABLE_NAME " SET randomNumber = v.randomNumber " \
-	"FROM (VALUES(%" PRIu32 ", %" PRIu32 ")"
-
-#define UPDATE_QUERY_ELEM ", (%" PRIu32 ", %" PRIu32 ")"
-#define UPDATE_QUERY_END ") AS v (id, randomNumber) WHERE " WORLD_TABLE_NAME ".id = v.id;"
+// UPDATE_QUERY_MIDDLE, UPDATE_QUERY_ELEM2, and UPDATE_QUERY_END are changed.
+#define UPDATE_QUERY_BEGIN "UPDATE " WORLD_TABLE_NAME " SET randomNumber = CASE id "
+#define UPDATE_QUERY_ELEM "WHEN %" PRIu32 " THEN %" PRIu32 " "
+#define UPDATE_QUERY_MIDDLE "ELSE randomNumber END WHERE id IN (%" PRIu32
+#define UPDATE_QUERY_ELEM2 ",%" PRIu32
+#define UPDATE_QUERY_END ");"
 
 #define MAX_UPDATE_QUERY_LEN(n) \
-	(sizeof(UPDATE_QUERY_BEGIN) + sizeof(UPDATE_QUERY_END) - sizeof(UPDATE_QUERY_ELEM) + \
-	 (n) * (sizeof(UPDATE_QUERY_ELEM) - 1 + \
-	        2 * (sizeof(MKSTR(MAX_ID)) - 1) - 2 * (sizeof(PRIu32) - 1) - 2))
+	(sizeof(UPDATE_QUERY_BEGIN) + sizeof(UPDATE_QUERY_MIDDLE) + \
+	 sizeof(UPDATE_QUERY_END) - 1 - sizeof(UPDATE_QUERY_ELEM2) + \
+	 (n) * (sizeof(UPDATE_QUERY_ELEM) - 1 + sizeof(UPDATE_QUERY_ELEM2) - 1 + \
+	        3 * (sizeof(MKSTR(MAX_ID)) - 1) - 3 * (sizeof(PRIu32) - 1) - 3))
 
 #define USE_CACHE 2
 #define WORLD_QUERY "SELECT * FROM " WORLD_TABLE_NAME " WHERE id = $1::integer;"
@@ -336,13 +336,8 @@ static void do_updates(multiple_query_ctx_t *query_ctx)
 	query_ctx->query_param->param.paramLengths = NULL;
 	query_ctx->query_param->param.paramValues = NULL;
 	query_ctx->query_param->param.flags = 0;
-	query_ctx->res->random_number = 1 + get_random_number(MAX_ID, &query_ctx->ctx->random_seed);
 
-	int c = snprintf(iter,
-	                 sz,
-	                 UPDATE_QUERY_BEGIN,
-	                 query_ctx->res->id,
-	                 query_ctx->res->random_number);
+	int c = snprintf(iter, sz, UPDATE_QUERY_BEGIN);
 
 	if ((size_t) c >= sz)
 		goto error;
@@ -350,7 +345,7 @@ static void do_updates(multiple_query_ctx_t *query_ctx)
 	iter += c;
 	sz -= c;
 
-	for (size_t i = 1; i < query_ctx->num_result; i++) {
+	for (size_t i = 0; i < query_ctx->num_result; i++) {
 		query_ctx->res[i].random_number = 1 + get_random_number(MAX_ID,
 		                                                        &query_ctx->ctx->random_seed);
 		c = snprintf(iter,
@@ -366,6 +361,24 @@ static void do_updates(multiple_query_ctx_t *query_ctx)
 		sz -= c;
 	}
 
+	c = snprintf(iter, sz, UPDATE_QUERY_MIDDLE, query_ctx->res->id);
+
+	if ((size_t) c >= sz)
+		goto error;
+
+	iter += c;
+	sz -= c;
+
+	for (size_t i = 1; i < query_ctx->num_result; i++) {
+		c = snprintf(iter, sz, UPDATE_QUERY_ELEM2, query_ctx->res[i].id);
+
+		if ((size_t) c >= sz)
+			goto error;
+
+		iter += c;
+		sz -= c;
+	}
+
 	c = snprintf(iter, sz, UPDATE_QUERY_END);
 
 	if ((size_t) c >= sz)

+ 1 - 0
frameworks/CSharp/aspnetcore/aspnetcore.dockerfile

@@ -5,6 +5,7 @@ RUN dotnet publish -c Release -o out /p:DatabaseProvider=Npgsql
 
 FROM mcr.microsoft.com/dotnet/aspnet:8.0.0-rc.2 AS runtime
 ENV URLS http://+:8080
+ENV DOTNET_SYSTEM_NET_SOCKETS_INLINE_COMPLETIONS 1
 
 WORKDIR /app
 COPY --from=build /app/out ./

+ 1 - 2
frameworks/FSharp/giraffe/README.md

@@ -10,7 +10,7 @@ This application tests Giraffe in 3 modes:
 
 **Language**
 
-* F# 6.0
+* F# 8.0
 
 **Platforms**
 
@@ -32,5 +32,4 @@ All source code is inside `Program.fs`.
 App listens for a single command line argument to pick the desired JSON implementation:
 
     - `system`: `System.Text.Json`
-    - `utf8`: `Utf8Json`
     - `newtonsoft`: `Newtonsoft.Json`

+ 0 - 18
frameworks/FSharp/giraffe/benchmark_config.json

@@ -22,24 +22,6 @@
         "notes": "",
         "versus": "aspcore"
       },
-      "utf8json": {
-        "json_url": "/json",
-        "port": 8080,
-        "approach": "Realistic",
-        "classification": "Micro",
-        "database": "None",
-        "framework": "giraffe",
-        "language": "F#",
-        "orm": "Raw",
-        "platform": ".NET",
-        "flavor": "CoreCLR",
-        "webserver": "Kestrel",
-        "os": "Linux",
-        "database_os": "Linux",
-        "display_name": "Giraffe, Utf8Json",
-        "notes": "",
-        "versus": "aspcore"
-      },
       "newtonsoft": {
         "json_url": "/json",
         "port": 8080,

+ 0 - 12
frameworks/FSharp/giraffe/config.toml

@@ -26,15 +26,3 @@ orm = "Raw"
 platform = ".NET"
 webserver = "Kestrel"
 versus = "aspcore"
-
-[utf8json]
-urls.json = "/json"
-approach = "Realistic"
-classification = "Micro"
-database = "None"
-database_os = "Linux"
-os = "Linux"
-orm = "Raw"
-platform = ".NET"
-webserver = "Kestrel"
-versus = "aspcore"

+ 4 - 4
frameworks/FSharp/giraffe/giraffe-newtonsoft.dockerfile

@@ -1,14 +1,14 @@
-FROM mcr.microsoft.com/dotnet/sdk:7.0.100 AS build
+FROM mcr.microsoft.com/dotnet/sdk:8.0.100 AS build
 WORKDIR /app
 COPY src/App .
 RUN dotnet publish -c Release -o out
 
-FROM mcr.microsoft.com/dotnet/aspnet:7.0 AS runtime
+FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS runtime
 ENV ASPNETCORE_URLS http://+:8080
 
 # Full PGO
-ENV DOTNET_TieredPGO 1 
-ENV DOTNET_TC_QuickJitForLoops 1 
+ENV DOTNET_TieredPGO 1
+ENV DOTNET_TC_QuickJitForLoops 1
 ENV DOTNET_ReadyToRun 0
 
 WORKDIR /app

+ 0 - 19
frameworks/FSharp/giraffe/giraffe-utf8json.dockerfile

@@ -1,19 +0,0 @@
-FROM mcr.microsoft.com/dotnet/sdk:7.0.100 AS build
-WORKDIR /app
-COPY src/App .
-RUN dotnet publish -c Release -o out
-
-FROM mcr.microsoft.com/dotnet/aspnet:7.0 AS runtime
-ENV ASPNETCORE_URLS http://+:8080
-
-# Full PGO
-ENV DOTNET_TieredPGO 1 
-ENV DOTNET_TC_QuickJitForLoops 1 
-ENV DOTNET_ReadyToRun 0
-
-WORKDIR /app
-COPY --from=build /app/out ./
-
-EXPOSE 8080
-
-ENTRYPOINT ["dotnet", "App.dll", "utf8"]

+ 4 - 4
frameworks/FSharp/giraffe/giraffe.dockerfile

@@ -1,14 +1,14 @@
-FROM mcr.microsoft.com/dotnet/sdk:7.0.100 AS build
+FROM mcr.microsoft.com/dotnet/sdk:8.0.100 AS build
 WORKDIR /app
 COPY src/App .
 RUN dotnet publish -c Release -o out
 
-FROM mcr.microsoft.com/dotnet/aspnet:7.0 AS runtime
+FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS runtime
 ENV ASPNETCORE_URLS http://+:8080
 
 # Full PGO
-ENV DOTNET_TieredPGO 1 
-ENV DOTNET_TC_QuickJitForLoops 1 
+ENV DOTNET_TieredPGO 1
+ENV DOTNET_TC_QuickJitForLoops 1
 ENV DOTNET_ReadyToRun 0
 
 WORKDIR /app

+ 5 - 8
frameworks/FSharp/giraffe/src/App/App.fsproj

@@ -1,18 +1,15 @@
 <Project Sdk="Microsoft.NET.Sdk.Web">
 
   <PropertyGroup>
-    <TargetFramework>net7.0</TargetFramework>
+    <TargetFramework>net8.0</TargetFramework>
     <EnableDefaultContentItems>false</EnableDefaultContentItems>
-
-    <!-- Settings applicable to JIT-based deployment -->
-    <TieredPGO>true</TieredPGO>
   </PropertyGroup>
 
   <ItemGroup>
-    <PackageReference Update="FSharp.Core" Version="7.0.0" />
-    <PackageReference Include="Dapper" Version="2.0.123" />
-    <PackageReference Include="Giraffe" Version="6.0.0" />
-    <PackageReference Include="Npgsql" Version="7.0.1" />
+    <PackageReference Update="FSharp.Core" Version="8.0.100" />
+    <PackageReference Include="Dapper" Version="2.1.21" />
+    <PackageReference Include="Giraffe" Version="6.2.0" />
+    <PackageReference Include="Npgsql" Version="8.0.0-rc.2" />
   </ItemGroup>
 
   <ItemGroup>

+ 3 - 8
frameworks/FSharp/giraffe/src/App/Program.fs

@@ -17,7 +17,6 @@ module Common =
 
     type JsonMode =
         | System
-        | Utf8
         | Newtonsoft
 
     let FortuneComparer =
@@ -109,12 +108,11 @@ module Main =
     open Microsoft.Extensions.Hosting
     open Microsoft.Extensions.Logging
 
-    [<EntryPoint>]    
+    [<EntryPoint>]
     let main args =
         let jsonMode =
             match args with
             | [| "newtonsoft" |] -> Newtonsoft
-            | [| "utf8" |]       -> Utf8
             | _                  -> System
 
         printfn $"Running with %A{jsonMode} JSON serializer"
@@ -124,9 +122,6 @@ module Main =
             | System ->
                 SystemTextJson.Serializer(SystemTextJson.Serializer.DefaultOptions)
                 :> Json.ISerializer
-            | Utf8 ->
-                Utf8Json.Serializer(Utf8Json.Serializer.DefaultResolver)
-                :> Json.ISerializer
             | Newtonsoft ->
                 NewtonsoftJson.Serializer(NewtonsoftJson.Serializer.DefaultSettings)
                 :> Json.ISerializer
@@ -136,7 +131,7 @@ module Main =
         builder.Services
             .AddSingleton(jsonSerializer)
             .AddGiraffe() |> ignore
-            
+
         builder.Logging.ClearProviders() |> ignore
 
         let app = builder.Build()
@@ -145,5 +140,5 @@ module Main =
            .UseGiraffe HttpHandlers.endpoints |> ignore
 
         app.Run()
-        
+
         0

+ 1 - 1
frameworks/FSharp/zebra/README.md

@@ -7,7 +7,7 @@ Zebra is a new F# functional Asp.net Framework Wrapper that utalises a shared st
 
 **Language**
 
-* F# 6.0
+* F# 8.0
 
 **Platforms**
 

+ 4 - 6
frameworks/FSharp/zebra/src/App/App.fsproj

@@ -1,20 +1,18 @@
 <Project Sdk="Microsoft.NET.Sdk.Web">
 
   <PropertyGroup>
-    <TargetFramework>net7.0</TargetFramework>
+    <TargetFramework>net8.0</TargetFramework>
     <DebugType>portable</DebugType>
     <AssemblyName>App</AssemblyName>
     <OutputType>Exe</OutputType>
     <EnableDefaultContentItems>false</EnableDefaultContentItems>
-    <!-- Settings applicable to JIT-based deployment -->
-    <TieredPGO>true</TieredPGO>
   </PropertyGroup>
 
   <ItemGroup>
-    <PackageReference Include="Dapper" Version="2.0.123" />
-    <PackageReference Include="Npgsql" Version="7.0.0" />
+    <PackageReference Include="Dapper" Version="2.1.21" />
+    <PackageReference Include="Npgsql" Version="8.0.0-rc.2" />
     <PackageReference Include="Utf8Json" Version="1.3.7" />
-    <PackageReference Update="FSharp.Core" Version="7.0.0" />
+    <PackageReference Update="FSharp.Core" Version="8.0.100" />
   </ItemGroup>
 
   <ItemGroup>

+ 4 - 4
frameworks/FSharp/zebra/zebra-simple.dockerfile

@@ -1,12 +1,12 @@
-FROM mcr.microsoft.com/dotnet/sdk:7.0.100 AS build
+FROM mcr.microsoft.com/dotnet/sdk:8.0.100 AS build
 WORKDIR /app
 COPY src/App .
 RUN dotnet publish -c Release -o out
 
-FROM mcr.microsoft.com/dotnet/aspnet:7.0 AS runtime
+FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS runtime
 # Full PGO
-ENV DOTNET_TieredPGO 1 
-ENV DOTNET_TC_QuickJitForLoops 1 
+ENV DOTNET_TieredPGO 1
+ENV DOTNET_TC_QuickJitForLoops 1
 ENV DOTNET_ReadyToRun 0
 
 ENV ASPNETCORE_URLS http://+:8080

+ 4 - 4
frameworks/FSharp/zebra/zebra.dockerfile

@@ -1,12 +1,12 @@
-FROM mcr.microsoft.com/dotnet/sdk:7.0.100 AS build
+FROM mcr.microsoft.com/dotnet/sdk:8.0.100 AS build
 WORKDIR /app
 COPY src/App .
 RUN dotnet publish -c Release -o out
 
-FROM mcr.microsoft.com/dotnet/aspnet:7.0 AS runtime
+FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS runtime
 # Full PGO
-ENV DOTNET_TieredPGO 1 
-ENV DOTNET_TC_QuickJitForLoops 1 
+ENV DOTNET_TieredPGO 1
+ENV DOTNET_TC_QuickJitForLoops 1
 ENV DOTNET_ReadyToRun 0
 
 ENV ASPNETCORE_URLS http://+:8080

+ 6 - 5
frameworks/JavaScript/nodejs/app.js

@@ -1,5 +1,6 @@
-const cluster = require('cluster');
-const numCPUs = require('os').cpus().length;
+const cluster = require('node:cluster');
+const { availableParallelism } = require('node:os');
+const numCPUs = availableParallelism();
 
 process.env.NODE_HANDLER = 'postgres';
 
@@ -13,18 +14,18 @@ if (process.env.TFB_TEST_NAME === 'nodejs-mongodb') {
   process.env.NODE_HANDLER = 'mysql-raw';
 } else if (process.env.TFB_TEST_NAME === 'nodejs-postgres') {
   process.env.NODE_HANDLER = 'sequelize-postgres';
-}else if (process.env.TFB_TEST_NAME === 'nodejs-postgresjs-raw') {
+} else if (process.env.TFB_TEST_NAME === 'nodejs-postgresjs-raw') {
   process.env.NODE_HANDLER = 'postgres';
 }
 
-if (cluster.isPrimary) {
+if (numCPUs > 1 && cluster.isPrimary) {
   console.log(`Primary ${process.pid} is running`);
 
   // Fork workers.
   for (let i = 0; i < numCPUs; i++) {
     cluster.fork();
   }
-
+  
   cluster.on('exit', (worker, code, signal) => {
     console.log(`worker ${worker.process.pid} died`);
     process.exit(1);

+ 1 - 1
frameworks/JavaScript/nodejs/create-server.js

@@ -1,7 +1,7 @@
 // Forked workers will run this code when found to not be
 // the master of the cluster.
 
-const http = require('http');
+const http = require('node:http');
 const parseurl = require('parseurl'); // faster than native nodejs url package
 
 // Initialize routes & their handlers (once)

+ 6 - 6
frameworks/JavaScript/nodejs/handlers/postgres.js

@@ -17,14 +17,14 @@ const dbfind = async (id) =>
     (arr) => arr[0]
   );
 
-const dbbulkUpdate = async (worlds) =>
+const dbbulkUpdate = async (worlds) => {
+  const sorted = sql(worlds
+    .map((world) => [world.id, world.randomNumber])
+    .sort((a, b) => (a[0] < b[0] ? -1 : 1)));
   await sql`UPDATE world SET randomNumber = (update_data.randomNumber)::int
-  FROM (VALUES ${sql(
-    worlds
-      .map((world) => [world.id, world.randomNumber])
-      .sort((a, b) => (a[0] < b[0] ? -1 : 1))
-  )}) AS update_data (id, randomNumber)
+  FROM (VALUES ${sorted}) AS update_data (id, randomNumber)
   WHERE world.id = (update_data.id)::int`;
+};
 
 const dbgetAllWorlds = async () => sql`SELECT id, randomNumber FROM world`;
 

+ 11 - 12
frameworks/Kotlin/http4k/core-pgclient/src/main/kotlin/PostgresDatabase.kt

@@ -1,4 +1,3 @@
-import io.vertx.core.CompositeFuture
 import io.vertx.core.Future
 import io.vertx.core.Vertx
 import io.vertx.core.VertxOptions
@@ -46,17 +45,17 @@ class PostgresDatabase : Database {
                 (1..count).map { queryPool.findWorld(random.world()) }
             ).toCompletionStage().toCompletableFuture().get().list<World>()
 
-    override fun updateWorlds(count: Int) =
-        Future.all((1..count)
-            .map { queryPool.findWorld(random.world()) })
-            .map<List<World>>(CompositeFuture::list)
-            .toCompletionStage()
-            .thenCompose { worlds ->
-                updatePool.preparedQuery("UPDATE world SET randomnumber = $1 WHERE id = $2")
-                    .executeBatch((1..count).map { Tuple.of(random.world(), random.world()) })
-                    .toCompletionStage()
-                    .thenApply { worlds }
-            }.toCompletableFuture().get()
+    override fun updateWorlds(count: Int) = (1..count).map {
+            queryPool.findWorld(random.world())
+                .flatMap { world ->
+                    updatePool.preparedQuery("UPDATE world SET randomnumber = $1 WHERE id = $2")
+                        .execute(Tuple.of(random.world(), world.first))
+                        .map { world }
+                }
+                .toCompletionStage()
+                .toCompletableFuture()
+                .get()
+        }
 
     override fun fortunes() = queryPool.preparedQuery("SELECT id, message FROM fortune")
         .execute()

+ 1 - 1
frameworks/Python/aiohttp/requirements.txt

@@ -1,4 +1,4 @@
-aiohttp==3.8.5
+aiohttp==3.9.0
 asyncpg==0.25.0
 cchardet==2.1.7
 gunicorn==20.1

+ 1 - 1
frameworks/Python/api_hour/requirements.txt

@@ -1,4 +1,4 @@
-aiohttp==3.8.6
+aiohttp==3.9.0
 -e git+https://github.com/Eyepea/aiohttp_jinja2.git@c9675e5c1e1ee7741b30aea8d8fbffcde016c7a0#egg=aiohttp_jinja2-master
 aiopg==0.7.0
 -e git+https://github.com/Eyepea/API-Hour.git@577abbdcbb8cc2810dad46e260b338b15db4d0e3#egg=api_hour-master

+ 1 - 1
frameworks/Ruby/hanami/config/auto_tune.rb

@@ -8,7 +8,7 @@
 require 'etc'
 
 KB_PER_WORKER = 128 * 1_024 # average of peak PSS of single-threaded processes (watch smem -k)
-MIN_WORKERS = 15
+MIN_WORKERS = 2
 MAX_WORKERS_PER_VCPU = 1.25 # virtual/logical
 MIN_THREADS_PER_WORKER = 1
 MAX_THREADS = Integer(ENV['MAX_CONCURRENCY'] || 256)

+ 1 - 1
frameworks/Ruby/rack/config/auto_tune.rb

@@ -8,7 +8,7 @@
 require 'etc'
 
 KB_PER_WORKER = 128 * 1_024 # average of peak PSS of single-threaded processes (watch smem -k)
-MIN_WORKERS = 15
+MIN_WORKERS = 2
 MAX_WORKERS_PER_VCPU = 1.25 # virtual/logical
 MIN_THREADS_PER_WORKER = 1
 MAX_THREADS = Integer(ENV['MAX_CONCURRENCY'] || 256)

+ 1 - 1
frameworks/Ruby/rails/config/database.yml

@@ -5,7 +5,7 @@ default: &default
   password: benchmarkdbpass
   host: tfb-database
   timeout: 5000
-  pool: <%= require_relative 'auto_tune'; auto_tune.reduce(:*) %>
+  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
 
 development:
   <<: *default

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

@@ -1,4 +1,4 @@
-FROM rust:1.60
+FROM rust:1.65
 
 WORKDIR /gotham
 COPY ./src ./src

+ 1 - 1
frameworks/Rust/ntex/src/main.rs

@@ -58,7 +58,7 @@ async fn main() -> std::io::Result<()> {
                 .client_timeout(Seconds(0))
                 .h1(web::App::new().service(json).service(plaintext).finish())
         })?
-        .workers(num_cpus::get_physical())
+        .workers(num_cpus::get())
         .run()
         .await
 }

+ 1 - 1
frameworks/Rust/ntex/src/main_db.rs

@@ -99,7 +99,7 @@ async fn main() -> std::io::Result<()> {
                 .client_timeout(Seconds(0))
                 .h1(AppFactory)
         })?
-        .workers(num_cpus::get_physical())
+        .workers(num_cpus::get())
         .run()
         .await
 }

+ 1 - 1
frameworks/Rust/ntex/src/main_plt.rs

@@ -87,7 +87,7 @@ async fn main() -> io::Result<()> {
                 codec: h1::Codec::default(),
             })
         })?
-        .workers(num_cpus::get_physical())
+        .workers(num_cpus::get())
         .run()
         .await
 }

+ 352 - 55
frameworks/Rust/xitca-web/Cargo.lock

@@ -17,6 +17,17 @@ version = "1.0.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
 
+[[package]]
+name = "async-trait"
+version = "0.1.74"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a66537f1bb974b254c98ed142ff995236e81b9d0fe4db0575f46612cb15eb0f9"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
 [[package]]
 name = "atoi"
 version = "2.0.0"
@@ -32,6 +43,55 @@ version = "1.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
 
+[[package]]
+name = "axum"
+version = "0.6.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3b829e4e32b91e643de6eafe82b1d90675f5874230191a4ffbc1b336dec4d6bf"
+dependencies = [
+ "async-trait",
+ "axum-core",
+ "bitflags 1.3.2",
+ "bytes",
+ "futures-util",
+ "http",
+ "http-body",
+ "hyper",
+ "itoa",
+ "matchit",
+ "memchr",
+ "mime",
+ "percent-encoding",
+ "pin-project-lite",
+ "rustversion",
+ "serde",
+ "serde_json",
+ "serde_path_to_error",
+ "serde_urlencoded",
+ "sync_wrapper",
+ "tokio",
+ "tower",
+ "tower-layer",
+ "tower-service",
+]
+
+[[package]]
+name = "axum-core"
+version = "0.3.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "759fa577a247914fd3f7f76d62972792636412fbfd634cd452f6a385a74d2d2c"
+dependencies = [
+ "async-trait",
+ "bytes",
+ "futures-util",
+ "http",
+ "http-body",
+ "mime",
+ "rustversion",
+ "tower-layer",
+ "tower-service",
+]
+
 [[package]]
 name = "backtrace"
 version = "0.3.69"
@@ -49,9 +109,9 @@ dependencies = [
 
 [[package]]
 name = "base64"
-version = "0.21.4"
+version = "0.21.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9ba43ea6f343b788c8764558649e08df62f86c6ef251fdaeb1ffd010a9ae50a2"
+checksum = "35636a1494ede3b646cc98f74f8e62c773a38a659ebc777a2cf26b9b74171df9"
 
 [[package]]
 name = "bitflags"
@@ -59,6 +119,12 @@ version = "1.3.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
 
+[[package]]
+name = "bitflags"
+version = "2.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07"
+
 [[package]]
 name = "block-buffer"
 version = "0.10.4"
@@ -97,9 +163,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
 
 [[package]]
 name = "cpufeatures"
-version = "0.2.9"
+version = "0.2.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a17b76ff3a4162b0b27f354a0c87015ddad39d35f9c0c36607a3bdd175dde1f1"
+checksum = "ce420fe07aecd3e67c5f910618fe65e94158f6dcc0adf44e00d69ce2bdfe0fd0"
 dependencies = [
  "libc",
 ]
@@ -155,11 +221,47 @@ version = "1.0.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
 
+[[package]]
+name = "form_urlencoded"
+version = "1.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456"
+dependencies = [
+ "percent-encoding",
+]
+
+[[package]]
+name = "futures-channel"
+version = "0.3.29"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ff4dd66668b557604244583e3e1e1eada8c5c2e96a6d0d6653ede395b78bbacb"
+dependencies = [
+ "futures-core",
+]
+
 [[package]]
 name = "futures-core"
-version = "0.3.28"
+version = "0.3.29"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "eb1d22c66e66d9d72e1758f0bd7d4fd0bee04cad842ee34587d68c07e45d088c"
+
+[[package]]
+name = "futures-task"
+version = "0.3.29"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c"
+checksum = "efd193069b0ddadc69c46389b740bbccdd97203899b48d09c5f7969591d6bae2"
+
+[[package]]
+name = "futures-util"
+version = "0.3.29"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a19526d624e703a3179b3d322efec918b6246ea0fa51d41124525f00f1cc8104"
+dependencies = [
+ "futures-core",
+ "futures-task",
+ "pin-project-lite",
+ "pin-utils",
+]
 
 [[package]]
 name = "generic-array"
@@ -173,9 +275,9 @@ dependencies = [
 
 [[package]]
 name = "getrandom"
-version = "0.2.10"
+version = "0.2.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427"
+checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f"
 dependencies = [
  "cfg-if",
  "libc",
@@ -184,9 +286,9 @@ dependencies = [
 
 [[package]]
 name = "gimli"
-version = "0.28.0"
+version = "0.28.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0"
+checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253"
 
 [[package]]
 name = "hermit-abi"
@@ -214,15 +316,32 @@ dependencies = [
 
 [[package]]
 name = "http"
-version = "0.2.9"
+version = "0.2.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482"
+checksum = "8947b1a6fad4393052c7ba1f4cd97bed3e953a95c79c92ad9b051a04611d9fbb"
 dependencies = [
  "bytes",
  "fnv",
  "itoa",
 ]
 
+[[package]]
+name = "http-body"
+version = "0.4.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1"
+dependencies = [
+ "bytes",
+ "http",
+ "pin-project-lite",
+]
+
+[[package]]
+name = "http-range-header"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "add0ab9360ddbd88cfeb3bd9574a1d85cfdfa14db10b3e21d3700dbc4328758f"
+
 [[package]]
 name = "httparse"
 version = "1.8.0"
@@ -235,13 +354,36 @@ version = "1.0.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9"
 
+[[package]]
+name = "hyper"
+version = "0.14.27"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ffb1cfd654a8219eaef89881fdb3bb3b1cdc5fa75ded05d6933b2b382e395468"
+dependencies = [
+ "bytes",
+ "futures-channel",
+ "futures-core",
+ "futures-util",
+ "http",
+ "http-body",
+ "httparse",
+ "httpdate",
+ "itoa",
+ "pin-project-lite",
+ "socket2 0.4.10",
+ "tokio",
+ "tower-service",
+ "tracing",
+ "want",
+]
+
 [[package]]
 name = "io-uring"
 version = "0.5.13"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "dd1e1a01cfb924fd8c5c43b6827965db394f5a3a16c599ce03452266e1cf984c"
 dependencies = [
- "bitflags",
+ "bitflags 1.3.2",
  "libc",
 ]
 
@@ -259,9 +401,9 @@ checksum = "9028f49264629065d057f340a86acb84867925865f73bbf8d47b4d149a7e88b8"
 
 [[package]]
 name = "libc"
-version = "0.2.149"
+version = "0.2.150"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a08173bc88b7955d1b3145aa561539096c421ac8debde8cbc3612ec635fee29b"
+checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c"
 
 [[package]]
 name = "libmimalloc-sys"
@@ -273,6 +415,18 @@ dependencies = [
  "libc",
 ]
 
+[[package]]
+name = "log"
+version = "0.4.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f"
+
+[[package]]
+name = "matchit"
+version = "0.7.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94"
+
 [[package]]
 name = "md-5"
 version = "0.10.6"
@@ -298,6 +452,12 @@ dependencies = [
  "libmimalloc-sys",
 ]
 
+[[package]]
+name = "mime"
+version = "0.3.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
+
 [[package]]
 name = "miniz_oxide"
 version = "0.7.1"
@@ -309,8 +469,8 @@ dependencies = [
 
 [[package]]
 name = "mio"
-version = "0.8.8"
-source = "git+https://github.com/fakeshadow/mio.git?rev=eb67f6794edba8bc2e973ddef32e066b41ff812a#eb67f6794edba8bc2e973ddef32e066b41ff812a"
+version = "0.8.9"
+source = "git+https://github.com/fakeshadow/mio.git?rev=52b72d372bfe5807755b7f5e3e1edf282954d6ba#52b72d372bfe5807755b7f5e3e1edf282954d6ba"
 dependencies = [
  "libc",
  "wasi",
@@ -351,11 +511,37 @@ dependencies = [
  "memchr",
 ]
 
+[[package]]
+name = "once_cell"
+version = "1.18.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
+
 [[package]]
 name = "percent-encoding"
-version = "2.3.0"
+version = "2.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
+
+[[package]]
+name = "pin-project"
+version = "1.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fda4ed1c6c173e3fc7a83629421152e01d7b1f9b7f65fb301e490e8cfc656422"
+dependencies = [
+ "pin-project-internal",
+]
+
+[[package]]
+name = "pin-project-internal"
+version = "1.1.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94"
+checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
 
 [[package]]
 name = "pin-project-lite"
@@ -363,6 +549,12 @@ version = "0.2.13"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58"
 
+[[package]]
+name = "pin-utils"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
+
 [[package]]
 name = "postgres-protocol"
 version = "0.6.6"
@@ -400,9 +592,9 @@ checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
 
 [[package]]
 name = "proc-macro2"
-version = "1.0.69"
+version = "1.0.70"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da"
+checksum = "39278fbbf5fb4f646ce651690877f89d1c5811a3d4acb27700c1cb3cdb78fd3b"
 dependencies = [
  "unicode-ident",
 ]
@@ -452,7 +644,7 @@ version = "0.3.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29"
 dependencies = [
- "bitflags",
+ "bitflags 1.3.2",
 ]
 
 [[package]]
@@ -461,6 +653,12 @@ version = "0.1.23"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76"
 
+[[package]]
+name = "rustversion"
+version = "1.0.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4"
+
 [[package]]
 name = "ryu"
 version = "1.0.15"
@@ -469,9 +667,9 @@ checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741"
 
 [[package]]
 name = "sailfish"
-version = "0.8.1"
+version = "0.8.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7861181faa2e413410444757deca246c70959cee725fbfd8f736a94a660eb377"
+checksum = "acd5f4680149b62b3478f6af08a8f1c37794bc1bc577e28874a4d0c70084d600"
 dependencies = [
  "itoap",
  "ryu",
@@ -481,9 +679,9 @@ dependencies = [
 
 [[package]]
 name = "sailfish-compiler"
-version = "0.8.1"
+version = "0.8.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7c38d77ced03b393e820ac70109857bd857f93e746f5d7d631829c9ee2e4f3fa"
+checksum = "67087aca4a3886686a88cee6835089c53e6143a0b8c5be01e63e4fe2f6dfe7cb"
 dependencies = [
  "filetime",
  "home",
@@ -495,9 +693,9 @@ dependencies = [
 
 [[package]]
 name = "sailfish-macros"
-version = "0.8.1"
+version = "0.8.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c8f73db14456f861a5c89166ab6ac76afd94b4d2a9416638ae2952ae051089c5"
+checksum = "e47e31910c5f9230e99992568d05a5968fe4f42a635c3f912c993e9f66a619a5"
 dependencies = [
  "proc-macro2",
  "sailfish-compiler",
@@ -511,18 +709,18 @@ checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294"
 
 [[package]]
 name = "serde"
-version = "1.0.189"
+version = "1.0.193"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8e422a44e74ad4001bdc8eede9a4570ab52f71190e9c076d14369f38b9200537"
+checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89"
 dependencies = [
  "serde_derive",
 ]
 
 [[package]]
 name = "serde_derive"
-version = "1.0.189"
+version = "1.0.193"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1e48d1f918009ce3145511378cf68d613e3b3d9137d67272562080d68a2b32d5"
+checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -531,10 +729,32 @@ dependencies = [
 
 [[package]]
 name = "serde_json"
-version = "1.0.107"
+version = "1.0.108"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b"
+dependencies = [
+ "itoa",
+ "ryu",
+ "serde",
+]
+
+[[package]]
+name = "serde_path_to_error"
+version = "0.1.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4beec8bce849d58d06238cb50db2e1c417cfeafa4c63f692b15c82b7c80f8335"
+dependencies = [
+ "itoa",
+ "serde",
+]
+
+[[package]]
+name = "serde_urlencoded"
+version = "0.7.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6b420ce6e3d8bd882e9b243c6eed35dbc9a6110c9769e74b584e0d68d1f20c65"
+checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd"
 dependencies = [
+ "form_urlencoded",
  "itoa",
  "ryu",
  "serde",
@@ -571,9 +791,9 @@ dependencies = [
 
 [[package]]
 name = "socket2"
-version = "0.4.9"
+version = "0.4.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "64a4a911eed85daf18834cfaa86a79b7d266ff93ff5ba14005426219480ed662"
+checksum = "9f7916fc008ca5542385b89a3d3ce689953c143e9304a9bf8beec1de48994c0d"
 dependencies = [
  "libc",
  "winapi",
@@ -581,9 +801,9 @@ dependencies = [
 
 [[package]]
 name = "socket2"
-version = "0.5.4"
+version = "0.5.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4031e820eb552adee9295814c0ced9e5cf38ddf1e8b7d566d6de8e2538ea989e"
+checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9"
 dependencies = [
  "libc",
  "windows-sys",
@@ -608,15 +828,21 @@ checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc"
 
 [[package]]
 name = "syn"
-version = "2.0.38"
+version = "2.0.39"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e96b79aaa137db8f61e26363a0c9b47d8b4ec75da28b7d1d614c2303e232408b"
+checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a"
 dependencies = [
  "proc-macro2",
  "quote",
  "unicode-ident",
 ]
 
+[[package]]
+name = "sync_wrapper"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160"
+
 [[package]]
 name = "tinyvec"
 version = "1.6.0"
@@ -634,9 +860,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
 
 [[package]]
 name = "tokio"
-version = "1.33.0"
+version = "1.34.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4f38200e3ef7995e5ef13baec2f432a6da0aa9ac495b2c0e8f3b7eec2c92d653"
+checksum = "d0c014766411e834f7af5b8f4cf46257aab4036ca95e9d2c144a10f59ad6f5b9"
 dependencies = [
  "backtrace",
  "libc",
@@ -644,7 +870,7 @@ dependencies = [
  "num_cpus",
  "pin-project-lite",
  "signal-hook-registry",
- "socket2 0.5.4",
+ "socket2 0.5.5",
  "windows-sys",
 ]
 
@@ -659,16 +885,63 @@ dependencies = [
  "libc",
  "scoped-tls",
  "slab",
- "socket2 0.4.9",
+ "socket2 0.4.10",
  "tokio",
 ]
 
+[[package]]
+name = "tower"
+version = "0.4.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c"
+dependencies = [
+ "futures-core",
+ "futures-util",
+ "pin-project",
+ "pin-project-lite",
+ "tokio",
+ "tower-layer",
+ "tower-service",
+ "tracing",
+]
+
+[[package]]
+name = "tower-http"
+version = "0.4.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "61c5bb1d698276a2443e5ecfabc1008bf15a36c12e6a7176e7bf089ea9131140"
+dependencies = [
+ "bitflags 2.4.1",
+ "bytes",
+ "futures-core",
+ "futures-util",
+ "http",
+ "http-body",
+ "http-range-header",
+ "pin-project-lite",
+ "tower-layer",
+ "tower-service",
+]
+
+[[package]]
+name = "tower-layer"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0"
+
+[[package]]
+name = "tower-service"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52"
+
 [[package]]
 name = "tracing"
 version = "0.1.40"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef"
 dependencies = [
+ "log",
  "pin-project-lite",
  "tracing-core",
 ]
@@ -678,6 +951,15 @@ name = "tracing-core"
 version = "0.1.32"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54"
+dependencies = [
+ "once_cell",
+]
+
+[[package]]
+name = "try-lock"
+version = "0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed"
 
 [[package]]
 name = "typenum"
@@ -712,6 +994,15 @@ version = "0.9.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
 
+[[package]]
+name = "want"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e"
+dependencies = [
+ "try-lock",
+]
+
 [[package]]
 name = "wasi"
 version = "0.11.0+wasi-snapshot-preview1"
@@ -809,7 +1100,7 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
 [[package]]
 name = "xitca-http"
 version = "0.1.0"
-source = "git+https://github.com/HFQR/xitca-web.git?rev=c0b85dfef6cb7917c36b8422de28a0beaaf4404a#c0b85dfef6cb7917c36b8422de28a0beaaf4404a"
+source = "git+https://github.com/HFQR/xitca-web.git?rev=23ad63cbb3a853a548bd447cc59625a5d7c5833e#23ad63cbb3a853a548bd447cc59625a5d7c5833e"
 dependencies = [
  "futures-core",
  "http",
@@ -817,7 +1108,7 @@ dependencies = [
  "httpdate",
  "itoa",
  "pin-project-lite",
- "socket2 0.5.4",
+ "socket2 0.5.5",
  "tokio",
  "tokio-uring",
  "tracing",
@@ -830,7 +1121,7 @@ dependencies = [
 [[package]]
 name = "xitca-io"
 version = "0.1.0"
-source = "git+https://github.com/HFQR/xitca-web.git?rev=c0b85dfef6cb7917c36b8422de28a0beaaf4404a#c0b85dfef6cb7917c36b8422de28a0beaaf4404a"
+source = "git+https://github.com/HFQR/xitca-web.git?rev=23ad63cbb3a853a548bd447cc59625a5d7c5833e#23ad63cbb3a853a548bd447cc59625a5d7c5833e"
 dependencies = [
  "bytes",
  "tokio",
@@ -841,7 +1132,7 @@ dependencies = [
 [[package]]
 name = "xitca-postgres"
 version = "0.1.0"
-source = "git+https://github.com/HFQR/xitca-web.git?rev=c0b85dfef6cb7917c36b8422de28a0beaaf4404a#c0b85dfef6cb7917c36b8422de28a0beaaf4404a"
+source = "git+https://github.com/HFQR/xitca-web.git?rev=23ad63cbb3a853a548bd447cc59625a5d7c5833e#23ad63cbb3a853a548bd447cc59625a5d7c5833e"
 dependencies = [
  "fallible-iterator",
  "percent-encoding",
@@ -857,7 +1148,7 @@ dependencies = [
 [[package]]
 name = "xitca-router"
 version = "0.1.0"
-source = "git+https://github.com/HFQR/xitca-web.git?rev=c0b85dfef6cb7917c36b8422de28a0beaaf4404a#c0b85dfef6cb7917c36b8422de28a0beaaf4404a"
+source = "git+https://github.com/HFQR/xitca-web.git?rev=23ad63cbb3a853a548bd447cc59625a5d7c5833e#23ad63cbb3a853a548bd447cc59625a5d7c5833e"
 dependencies = [
  "xitca-unsafe-collection",
 ]
@@ -865,9 +1156,9 @@ dependencies = [
 [[package]]
 name = "xitca-server"
 version = "0.1.0"
-source = "git+https://github.com/HFQR/xitca-web.git?rev=c0b85dfef6cb7917c36b8422de28a0beaaf4404a#c0b85dfef6cb7917c36b8422de28a0beaaf4404a"
+source = "git+https://github.com/HFQR/xitca-web.git?rev=23ad63cbb3a853a548bd447cc59625a5d7c5833e#23ad63cbb3a853a548bd447cc59625a5d7c5833e"
 dependencies = [
- "socket2 0.5.4",
+ "socket2 0.5.5",
  "tokio",
  "tokio-uring",
  "tracing",
@@ -879,12 +1170,12 @@ dependencies = [
 [[package]]
 name = "xitca-service"
 version = "0.1.0"
-source = "git+https://github.com/HFQR/xitca-web.git?rev=c0b85dfef6cb7917c36b8422de28a0beaaf4404a#c0b85dfef6cb7917c36b8422de28a0beaaf4404a"
+source = "git+https://github.com/HFQR/xitca-web.git?rev=23ad63cbb3a853a548bd447cc59625a5d7c5833e#23ad63cbb3a853a548bd447cc59625a5d7c5833e"
 
 [[package]]
 name = "xitca-unsafe-collection"
 version = "0.1.0"
-source = "git+https://github.com/HFQR/xitca-web.git?rev=c0b85dfef6cb7917c36b8422de28a0beaaf4404a#c0b85dfef6cb7917c36b8422de28a0beaaf4404a"
+source = "git+https://github.com/HFQR/xitca-web.git?rev=23ad63cbb3a853a548bd447cc59625a5d7c5833e#23ad63cbb3a853a548bd447cc59625a5d7c5833e"
 dependencies = [
  "bytes",
 ]
@@ -894,31 +1185,37 @@ name = "xitca-web"
 version = "0.1.0"
 dependencies = [
  "atoi",
+ "axum",
  "futures-core",
+ "http-body",
  "mimalloc",
  "nanorand",
+ "pin-project-lite",
  "sailfish",
  "serde",
  "serde_json",
  "tokio",
+ "tower",
+ "tower-http",
  "xitca-http",
  "xitca-io",
  "xitca-postgres",
  "xitca-server",
  "xitca-service",
  "xitca-unsafe-collection",
- "xitca-web 0.1.0 (git+https://github.com/HFQR/xitca-web.git?rev=c0b85dfef6cb7917c36b8422de28a0beaaf4404a)",
+ "xitca-web 0.1.0 (git+https://github.com/HFQR/xitca-web.git?rev=23ad63cbb3a853a548bd447cc59625a5d7c5833e)",
 ]
 
 [[package]]
 name = "xitca-web"
 version = "0.1.0"
-source = "git+https://github.com/HFQR/xitca-web.git?rev=c0b85dfef6cb7917c36b8422de28a0beaaf4404a#c0b85dfef6cb7917c36b8422de28a0beaaf4404a"
+source = "git+https://github.com/HFQR/xitca-web.git?rev=23ad63cbb3a853a548bd447cc59625a5d7c5833e#23ad63cbb3a853a548bd447cc59625a5d7c5833e"
 dependencies = [
  "futures-core",
  "pin-project-lite",
  "serde",
  "serde_json",
+ "tokio",
  "xitca-http",
  "xitca-server",
  "xitca-service",

+ 23 - 9
frameworks/Rust/xitca-web/Cargo.toml

@@ -18,6 +18,11 @@ name = "xitca-web-wasm"
 path = "./src/main_wasm.rs"
 required-features = ["web"]
 
+[[bin]]
+name = "xitca-web-axum"
+path = "./src/main_axum.rs"
+required-features = ["axum", "io-uring"]
+
 [features]
 # pg optional
 pg = ["xitca-postgres"]
@@ -31,6 +36,8 @@ web = ["xitca-web"]
 template = ["sailfish"]
 # io-uring optional
 io-uring = ["xitca-http/io-uring", "xitca-server/io-uring"]
+# axum optional
+axum = ["dep:axum", "http-body", "pin-project-lite", "tower", "tower-http"]
 
 [dependencies]
 xitca-http = "0.1"
@@ -52,6 +59,13 @@ xitca-postgres = { version = "0.1", features = ["single-thread"], optional = tru
 # template optional
 sailfish = { version = "0.8", default-features = false, features = ["derive", "perf-inline"], optional = true }
 
+# axum optional
+axum = { version = "0.6", optional = true }
+http-body = { version = "0.4", optional = true }
+pin-project-lite = { version = "0.2", optional = true }
+tower = { version = "0.4", optional = true }
+tower-http = { version = "0.4", features = ["set-header"], optional = true }
+
 # stuff can not be used or not needed in wasi target
 [target.'cfg(not(target_family = "wasm"))'.dependencies]
 futures-core = { version = "0.3", default-features = false }
@@ -66,13 +80,13 @@ codegen-units = 1
 panic = "abort"
 
 [patch.crates-io]
-xitca-http = { git = "https://github.com/HFQR/xitca-web.git", rev = "c0b85dfef6cb7917c36b8422de28a0beaaf4404a" }
-xitca-io = { git = "https://github.com/HFQR/xitca-web.git", rev = "c0b85dfef6cb7917c36b8422de28a0beaaf4404a" }
-xitca-postgres = { git = "https://github.com/HFQR/xitca-web.git", rev = "c0b85dfef6cb7917c36b8422de28a0beaaf4404a" }
-xitca-router = { git = "https://github.com/HFQR/xitca-web.git", rev = "c0b85dfef6cb7917c36b8422de28a0beaaf4404a" }
-xitca-server = { git = "https://github.com/HFQR/xitca-web.git", rev = "c0b85dfef6cb7917c36b8422de28a0beaaf4404a" }
-xitca-service = { git = "https://github.com/HFQR/xitca-web.git", rev = "c0b85dfef6cb7917c36b8422de28a0beaaf4404a" }
-xitca-unsafe-collection = { git = "https://github.com/HFQR/xitca-web.git", rev = "c0b85dfef6cb7917c36b8422de28a0beaaf4404a" }
-xitca-web = { git = "https://github.com/HFQR/xitca-web.git", rev = "c0b85dfef6cb7917c36b8422de28a0beaaf4404a" }
+xitca-http = { git = "https://github.com/HFQR/xitca-web.git", rev = "23ad63cbb3a853a548bd447cc59625a5d7c5833e" }
+xitca-io = { git = "https://github.com/HFQR/xitca-web.git", rev = "23ad63cbb3a853a548bd447cc59625a5d7c5833e" }
+xitca-postgres = { git = "https://github.com/HFQR/xitca-web.git", rev = "23ad63cbb3a853a548bd447cc59625a5d7c5833e" }
+xitca-router = { git = "https://github.com/HFQR/xitca-web.git", rev = "23ad63cbb3a853a548bd447cc59625a5d7c5833e" }
+xitca-server = { git = "https://github.com/HFQR/xitca-web.git", rev = "23ad63cbb3a853a548bd447cc59625a5d7c5833e" }
+xitca-service = { git = "https://github.com/HFQR/xitca-web.git", rev = "23ad63cbb3a853a548bd447cc59625a5d7c5833e" }
+xitca-unsafe-collection = { git = "https://github.com/HFQR/xitca-web.git", rev = "23ad63cbb3a853a548bd447cc59625a5d7c5833e" }
+xitca-web = { git = "https://github.com/HFQR/xitca-web.git", rev = "23ad63cbb3a853a548bd447cc59625a5d7c5833e" }
 
-mio = { git = "https://github.com/fakeshadow/mio.git", rev = "eb67f6794edba8bc2e973ddef32e066b41ff812a" }
+mio = { git = "https://github.com/fakeshadow/mio.git", rev = "52b72d372bfe5807755b7f5e3e1edf282954d6ba" }

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

@@ -63,6 +63,24 @@
         "display_name": "xitca-web [wasm]",
         "notes": "",
         "versus": ""
+      },
+      "axum": {
+        "json_url": "/json",
+        "plaintext_url": "/plaintext",
+        "port": 8080,
+        "approach": "Realistic",
+        "classification": "Micro",
+        "database": "none",
+        "framework": "axum [xitca]",
+        "language": "rust",
+        "orm": "raw",
+        "platform": "none",
+        "webserver": "xitca-server",
+        "os": "linux",
+        "database_os": "linux",
+        "display_name": "axum [xitca]",
+        "notes": "",
+        "versus": ""
       }
     }
   ]

+ 1 - 1
frameworks/Rust/xitca-web/rust-toolchain.toml

@@ -1,2 +1,2 @@
 [toolchain]
-channel = "nightly-2023-10-19"
+channel = "nightly-2023-11-24"

+ 16 - 23
frameworks/Rust/xitca-web/src/main.rs

@@ -8,7 +8,6 @@ mod util;
 use xitca_http::{
     body::Once,
     bytes::Bytes,
-    config::HttpServiceConfig,
     h1::RequestBody,
     http::{
         self,
@@ -31,23 +30,19 @@ type Request = http::Request<RequestExt<RequestBody>>;
 type Ctx<'a> = self::util::Ctx<'a, Request>;
 
 fn main() -> std::io::Result<()> {
+    let service = Router::new()
+        .insert("/plaintext", get(fn_service(plain_text)))
+        .insert("/json", get(fn_service(json)))
+        .insert("/db", get(fn_service(db)))
+        .insert("/fortunes", get(fn_service(fortunes)))
+        .insert("/queries", get(fn_service(queries)))
+        .insert("/updates", get(fn_service(updates)))
+        .enclosed_fn(middleware_fn)
+        .enclosed(context_mw())
+        .enclosed(HttpServiceBuilder::h1().io_uring());
+
     xitca_server::Builder::new()
-        .bind("xitca-web", "0.0.0.0:8080", || {
-            Router::new()
-                .insert("/plaintext", get(fn_service(plain_text)))
-                .insert("/json", get(fn_service(json)))
-                .insert("/db", get(fn_service(db)))
-                .insert("/fortunes", get(fn_service(fortunes)))
-                .insert("/queries", get(fn_service(queries)))
-                .insert("/updates", get(fn_service(updates)))
-                .enclosed_fn(middleware_fn)
-                .enclosed(context_mw())
-                .enclosed(
-                    HttpServiceBuilder::h1()
-                        .io_uring()
-                        .config(HttpServiceConfig::new().max_request_headers::<8>()),
-                )
-        })?
+        .bind("xitca-web", "0.0.0.0:8080", service)?
         .build()
         .wait()
 }
@@ -57,17 +52,15 @@ where
     S: for<'c> Service<Ctx<'c>, Response = Response, Error = E>,
 {
     service.call(req).await.map(|mut res| {
-        res.headers_mut().append(SERVER, SERVER_HEADER_VALUE);
+        res.headers_mut().insert(SERVER, SERVER_HEADER_VALUE);
         res
     })
 }
 
-const HELLO: Bytes = Bytes::from_static(b"Hello, World!");
-
 async fn plain_text(ctx: Ctx<'_>) -> HandleResult<Response> {
     let (req, _) = ctx.into_parts();
-    let mut res = req.into_response(HELLO);
-    res.headers_mut().append(CONTENT_TYPE, TEXT);
+    let mut res = req.into_response(Bytes::from_static(b"Hello, World!"));
+    res.headers_mut().insert(CONTENT_TYPE, TEXT);
     Ok(res)
 }
 
@@ -87,7 +80,7 @@ async fn fortunes(ctx: Ctx<'_>) -> HandleResult<Response> {
     use sailfish::TemplateOnce;
     let fortunes = state.client.tell_fortune().await?.render_once()?;
     let mut res = req.into_response(Bytes::from(fortunes));
-    res.headers_mut().append(CONTENT_TYPE, TEXT_HTML_UTF8);
+    res.headers_mut().insert(CONTENT_TYPE, TEXT_HTML_UTF8);
     Ok(res)
 }
 

+ 189 - 0
frameworks/Rust/xitca-web/src/main_axum.rs

@@ -0,0 +1,189 @@
+//! show case of axum running on proper thread per core server with io-uring enabled.
+
+#[global_allocator]
+static GLOBAL: mimalloc::MiMalloc = mimalloc::MiMalloc;
+
+mod ser;
+mod util;
+
+use axum::{
+    http::header::{HeaderValue, SERVER},
+    response::IntoResponse,
+    routing::{get, Router},
+    Json,
+};
+use tower_http::set_header::SetResponseHeaderLayer;
+
+use crate::tower_compat::TowerHttp;
+
+fn main() -> std::io::Result<()> {
+    let service = TowerHttp::service(|| async {
+        Router::new()
+            .route("/plaintext", get(plain_text))
+            .route("/json", get(json))
+            .layer(SetResponseHeaderLayer::if_not_present(
+                SERVER,
+                HeaderValue::from_static("A"),
+            ))
+    });
+
+    xitca_server::Builder::new()
+        .bind("xitca-axum", "0.0.0.0:8080", service)?
+        .build()
+        .wait()
+}
+
+async fn plain_text() -> &'static str {
+    "Hello, World!"
+}
+
+async fn json() -> impl IntoResponse {
+    Json(ser::Message::new())
+}
+
+mod tower_compat {
+    use std::{
+        cell::RefCell,
+        convert::Infallible,
+        error, fmt,
+        future::Future,
+        io,
+        marker::PhantomData,
+        net::SocketAddr,
+        pin::Pin,
+        task::{Context, Poll},
+    };
+
+    use axum::extract::ConnectInfo;
+    use futures_core::stream::Stream;
+    use http_body::Body;
+    use pin_project_lite::pin_project;
+    use xitca_http::{
+        body::none_body_hint,
+        bytes::Bytes,
+        h1::RequestBody,
+        http::{HeaderMap, Request, RequestExt, Response},
+        BodyError, HttpServiceBuilder,
+    };
+    use xitca_io::net::io_uring::TcpStream;
+    use xitca_service::{
+        fn_build, middleware::UncheckedReady, ready::ReadyService, Service, ServiceExt,
+    };
+    use xitca_unsafe_collection::fake_send_sync::FakeSend;
+
+    pub struct TowerHttp<S, B> {
+        service: RefCell<S>,
+        _p: PhantomData<fn(B)>,
+    }
+
+    impl<S, B> TowerHttp<S, B> {
+        pub fn service<F, Fut>(
+            service: F,
+        ) -> impl Service<
+            Response = impl ReadyService + Service<(TcpStream, SocketAddr)>,
+            Error = impl fmt::Debug,
+        >
+        where
+            F: Fn() -> Fut + Send + Sync + Clone,
+            Fut: Future<Output = S>,
+            S: tower::Service<Request<_RequestBody>, Response = Response<B>>,
+            S::Error: fmt::Debug,
+            B: Body<Data = Bytes> + Send + 'static,
+            B::Error: error::Error + Send + Sync,
+        {
+            fn_build(move |_| {
+                let service = service.clone();
+                async move {
+                    let service = service().await;
+                    Ok::<_, Infallible>(TowerHttp {
+                        service: RefCell::new(service),
+                        _p: PhantomData,
+                    })
+                }
+            })
+            .enclosed(UncheckedReady)
+            .enclosed(HttpServiceBuilder::h1().io_uring())
+        }
+    }
+
+    impl<S, B> Service<Request<RequestExt<RequestBody>>> for TowerHttp<S, B>
+    where
+        S: tower::Service<Request<_RequestBody>, Response = Response<B>>,
+        B: Body<Data = Bytes> + Send + 'static,
+        B::Error: error::Error + Send + Sync,
+    {
+        type Response = Response<ResponseBody<B>>;
+        type Error = S::Error;
+
+        async fn call(
+            &self,
+            req: Request<RequestExt<RequestBody>>,
+        ) -> Result<Self::Response, Self::Error> {
+            let (parts, ext) = req.into_parts();
+            let (ext, body) = ext.replace_body(());
+            let body = _RequestBody {
+                body: FakeSend::new(body),
+            };
+            let mut req = Request::from_parts(parts, body);
+            let _ = req.extensions_mut().insert(ConnectInfo(*ext.socket_addr()));
+            let fut = self.service.borrow_mut().call(req);
+            let (parts, body) = fut.await?.into_parts();
+            let body = ResponseBody { body };
+            let res = Response::from_parts(parts, body);
+            Ok(res)
+        }
+    }
+
+    pub struct _RequestBody {
+        body: FakeSend<RequestBody>,
+    }
+
+    impl Body for _RequestBody {
+        type Data = Bytes;
+        type Error = io::Error;
+
+        fn poll_data(
+            self: Pin<&mut Self>,
+            cx: &mut Context<'_>,
+        ) -> Poll<Option<Result<Self::Data, Self::Error>>> {
+            Pin::new(&mut *self.get_mut().body).poll_next(cx)
+        }
+
+        fn poll_trailers(
+            self: Pin<&mut Self>,
+            _: &mut Context<'_>,
+        ) -> Poll<Result<Option<HeaderMap>, Self::Error>> {
+            Poll::Ready(Ok(None))
+        }
+    }
+
+    pin_project! {
+        pub struct ResponseBody<B> {
+            #[pin]
+            body: B
+        }
+    }
+
+    impl<B> Stream for ResponseBody<B>
+    where
+        B: Body<Data = Bytes>,
+        B::Error: error::Error + Send + Sync + 'static,
+    {
+        type Item = Result<Bytes, BodyError>;
+
+        fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
+            self.project()
+                .body
+                .poll_data(cx)
+                .map_err(|e| BodyError::from(Box::new(e) as Box<dyn error::Error + Send + Sync>))
+        }
+
+        fn size_hint(&self) -> (usize, Option<usize>) {
+            if Body::is_end_stream(&self.body) {
+                return none_body_hint();
+            }
+            let hint = Body::size_hint(&self.body);
+            (hint.lower() as _, hint.upper().map(|u| u as _))
+        }
+    }
+}

+ 10 - 11
frameworks/Rust/xitca-web/src/main_iou.rs

@@ -38,18 +38,17 @@ type Request = http::Request<RequestExt<()>>;
 type Response = http::Response<Once<Bytes>>;
 
 fn main() -> io::Result<()> {
+    let service = fn_service(handler)
+        .enclosed(context_mw())
+        .enclosed(fn_build(|service| async {
+            Ok::<_, Infallible>(Http1IOU {
+                service,
+                date: DateTimeService::new(),
+            })
+        }))
+        .enclosed(UncheckedReady);
     xitca_server::Builder::new()
-        .bind("xitca-iou", "0.0.0.0:8080", || {
-            fn_service(handler)
-                .enclosed(context_mw())
-                .enclosed(fn_build(|service| async {
-                    Ok::<_, Infallible>(Http1IOU {
-                        service,
-                        date: DateTimeService::new(),
-                    })
-                }))
-                .enclosed(UncheckedReady)
-        })?
+        .bind("xitca-iou", "0.0.0.0:8080", service)?
         .build()
         .wait()
 }

+ 15 - 19
frameworks/Rust/xitca-web/src/main_wasm.rs

@@ -10,7 +10,7 @@ use xitca_web::{
     request::WebRequest,
     response::WebResponse,
     route::get,
-    App, HttpServer,
+    App,
 };
 
 use self::util::SERVER_HEADER_VALUE;
@@ -23,24 +23,20 @@ fn main() -> io::Result<()> {
 
     let listener = unsafe { TcpListener::from_raw_fd(fd) };
 
-    HttpServer::new(|| {
-        App::new()
-            .at(
-                "/json",
-                get(handler_service(|| async {
-                    Json::<ser::Message>(ser::Message::new())
-                })),
-            )
-            .at(
-                "/plaintext",
-                get(handler_service(|| async { "Hello, World!" })),
-            )
-            .enclosed_fn(middleware_fn)
-            .finish()
-    })
-    .listen(listener)?
-    .run()
-    .wait()
+    App::new()
+        .at(
+            "/json",
+            get(handler_service(|| async { Json(ser::Message::new()) })),
+        )
+        .at(
+            "/plaintext",
+            get(handler_service(|| async { "Hello, World!" })),
+        )
+        .enclosed_fn(middleware_fn)
+        .serve()
+        .listen(listener)?
+        .run()
+        .wait()
 }
 
 async fn middleware_fn<S, E>(service: &S, ctx: WebRequest<'_>) -> Result<WebResponse, E>

+ 2 - 0
frameworks/Rust/xitca-web/src/util.rs

@@ -30,6 +30,7 @@ pub type Error = Box<dyn std::error::Error + Send + Sync + 'static>;
 pub type HandleResult<T> = Result<T, Error>;
 
 #[cfg(not(target_arch = "wasm32"))]
+#[cfg(any(feature = "pg", feature = "pg-iou"))]
 mod non_wasm {
     use core::{cell::RefCell, future::Future, pin::Pin};
 
@@ -76,4 +77,5 @@ mod non_wasm {
 }
 
 #[cfg(not(target_arch = "wasm32"))]
+#[cfg(any(feature = "pg", feature = "pg-iou"))]
 pub use non_wasm::*;

+ 10 - 0
frameworks/Rust/xitca-web/xitca-web-axum.dockerfile

@@ -0,0 +1,10 @@
+FROM rust:1.74
+
+ADD ./ /xitca-web
+WORKDIR /xitca-web
+
+RUN cargo build --release --bin xitca-web-axum --features axum,io-uring
+
+EXPOSE 8080
+
+CMD ./target/release/xitca-web-axum

+ 6 - 7
frameworks/Rust/xitca-web/xitca-web-wasm.dockerfile

@@ -1,7 +1,7 @@
-ARG WASMTIME_VERSION=12.0.1
+ARG WASMTIME_VERSION=15.0.0
 ARG WASM_TARGET=wasm32-wasi-preview1-threads
 
-FROM rust:1.67 AS compile
+FROM rust:1.74 AS compile
 
 ARG WASMTIME_VERSION
 ARG WASM_TARGET
@@ -27,9 +27,8 @@ COPY --from=compile \
 /opt/xitca-web-wasm/
 EXPOSE 8080
 
-CMD /opt/xitca-web-wasm/wasmtime run /opt/xitca-web-wasm/xitca-web-wasm.wasm \
---wasm-features=threads \
---wasi-modules experimental-wasi-threads \
---allow-precompiled \
+CMD /opt/xitca-web-wasm/wasmtime run \
+--wasm all-proposals=y \
+--wasi threads=y,tcplisten=0.0.0.0:8080 \
 --env FD_COUNT=3 \
---tcplisten 0.0.0.0:8080
+/opt/xitca-web-wasm/xitca-web-wasm.wasm