diff --git a/frameworks/C++/just-boost/README.md b/frameworks/C++/just-boost/README.md new file mode 100644 index 00000000000..2c65928d229 --- /dev/null +++ b/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 diff --git a/frameworks/C++/just-boost/benchmark_config.json b/frameworks/C++/just-boost/benchmark_config.json new file mode 100644 index 00000000000..462fd21432c --- /dev/null +++ b/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": "" + } + } + ] +} diff --git a/frameworks/C++/just-boost/just-boost.dockerfile b/frameworks/C++/just-boost/just-boost.dockerfile new file mode 100644 index 00000000000..0eb409e1ab9 --- /dev/null +++ b/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"] diff --git a/frameworks/C++/just-boost/main.cpp b/frameworks/C++/just-boost/main.cpp new file mode 100644 index 00000000000..fc296da6837 --- /dev/null +++ b/frameworks/C++/just-boost/main.cpp @@ -0,0 +1,396 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(BOOST_ASIO_HAS_CO_AWAIT) + +#include + +namespace beast = boost::beast; // from +namespace http = beast::http; // from +namespace net = boost::asio; // from +using tcp = boost::asio::ip::tcp; // from +namespace json = boost::json; // from + +using tcp_stream = typename beast::tcp_stream::rebind_executor< + net::use_awaitable_t<>::executor_with_default>::other; + +namespace becpp +{ + +using result_ptr = std::unique_ptr; + +//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 +http::message_generator +handle_error( + http::request>&& req, + http::status status, + beast::string_view msg) +{ + http::response 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 +http::message_generator +handle_target( + http::request>&& req, + PGconn* conn = nullptr) +{ + static std::string msg = "Hello, World!"; + + //std::cout << "handle_target: " << req.target() << std::endl; + http::response 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 +http::message_generator +handle_request( + http::request>&& 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 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 +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 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 +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(std::atoi(becpp::env("BCPP_PORT", "8000"))); + auto const threads = std::max(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 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 diff --git a/frameworks/C++/userver/userver-bare.dockerfile b/frameworks/C++/userver/userver-bare.dockerfile index 1653e9d2da5..4b1210c8fe2 100644 --- a/frameworks/C++/userver/userver-bare.dockerfile +++ b/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 \ diff --git a/frameworks/C++/userver/userver.dockerfile b/frameworks/C++/userver/userver.dockerfile index a2a0df955ae..0c39abe0130 100644 --- a/frameworks/C++/userver/userver.dockerfile +++ b/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 \ diff --git a/frameworks/C++/userver/userver_benchmark/common/db_helpers.cpp b/frameworks/C++/userver/userver_benchmark/common/db_helpers.cpp index 9aaa6cbc6ae..899a2aaa87c 100644 --- a/frameworks/C++/userver/userver_benchmark/common/db_helpers.cpp +++ b/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); } diff --git a/frameworks/C++/userver/userver_benchmark/common/db_helpers.hpp b/frameworks/C++/userver/userver_benchmark/common/db_helpers.hpp index ae31d13a226..a4325c3b0fa 100644 --- a/frameworks/C++/userver/userver_benchmark/common/db_helpers.hpp +++ b/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 { diff --git a/frameworks/C++/userver/userver_benchmark/controllers/fortunes/handler.cpp b/frameworks/C++/userver/userver_benchmark/controllers/fortunes/handler.cpp index 9c09939f0ab..4c7619bc86d 100644 --- a/frameworks/C++/userver/userver_benchmark/controllers/fortunes/handler.cpp +++ b/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( 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>( - userver::storages::postgres::kRowTag); + return pg_->Execute(db_helpers::kClusterHostType, + select_all_fortunes_query_); }(); + auto fortunes = pg_result.AsContainer>( + userver::storages::postgres::kRowTag); fortunes.push_back({0, "Additional fortune added at request time."}); std::sort(fortunes.begin(), fortunes.end(), diff --git a/frameworks/C++/userver/userver_benchmark/controllers/updates/handler.cpp b/frameworks/C++/userver/userver_benchmark/controllers/updates/handler.cpp index f5242bc333f..4bf62bf645e 100644 --- a/frameworks/C++/userver/userver_benchmark/controllers/updates/handler.cpp +++ b/frameworks/C++/userver/userver_benchmark/controllers/updates/handler.cpp @@ -30,7 +30,7 @@ Handler::Handler(const userver::components::ComponentConfig& config, pg_{context.FindComponent("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( diff --git a/frameworks/C++/userver/userver_configs/static_config.yaml b/frameworks/C++/userver/userver_configs/static_config.yaml index 996dfd387fd..b4fad14911f 100644 --- a/frameworks/C++/userver/userver_configs/static_config.yaml +++ b/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 diff --git a/frameworks/C/h2o/h2o.dockerfile b/frameworks/C/h2o/h2o.dockerfile index 7994b193949..8a04c410cac 100644 --- a/frameworks/C/h2o/h2o.dockerfile +++ b/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 diff --git a/frameworks/C/h2o/src/database.c b/frameworks/C/h2o/src/database.c index 3cdc45913b6..59042b1dec3 100644 --- a/frameworks/C/h2o/src/database.c +++ b/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; } diff --git a/frameworks/C/h2o/src/handlers/world.c b/frameworks/C/h2o/src/handlers/world.c index da4188ca3eb..0a7aaf1d813 100644 --- a/frameworks/C/h2o/src/handlers/world.c +++ b/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) diff --git a/frameworks/CSharp/aspnetcore/aspnetcore.dockerfile b/frameworks/CSharp/aspnetcore/aspnetcore.dockerfile index d1e50dd88e0..90409f3b188 100644 --- a/frameworks/CSharp/aspnetcore/aspnetcore.dockerfile +++ b/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 ./ diff --git a/frameworks/FSharp/giraffe/README.md b/frameworks/FSharp/giraffe/README.md index b6a61090be7..fa4751bbda2 100644 --- a/frameworks/FSharp/giraffe/README.md +++ b/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` diff --git a/frameworks/FSharp/giraffe/benchmark_config.json b/frameworks/FSharp/giraffe/benchmark_config.json index 8dc135e931c..4384822a751 100644 --- a/frameworks/FSharp/giraffe/benchmark_config.json +++ b/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, diff --git a/frameworks/FSharp/giraffe/config.toml b/frameworks/FSharp/giraffe/config.toml index dfafd84d70d..15122b9ddba 100644 --- a/frameworks/FSharp/giraffe/config.toml +++ b/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" diff --git a/frameworks/FSharp/giraffe/giraffe-newtonsoft.dockerfile b/frameworks/FSharp/giraffe/giraffe-newtonsoft.dockerfile index e3b3ec0c3b5..b22de354452 100644 --- a/frameworks/FSharp/giraffe/giraffe-newtonsoft.dockerfile +++ b/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 diff --git a/frameworks/FSharp/giraffe/giraffe-utf8json.dockerfile b/frameworks/FSharp/giraffe/giraffe-utf8json.dockerfile deleted file mode 100644 index 52cbdae7283..00000000000 --- a/frameworks/FSharp/giraffe/giraffe-utf8json.dockerfile +++ /dev/null @@ -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"] diff --git a/frameworks/FSharp/giraffe/giraffe.dockerfile b/frameworks/FSharp/giraffe/giraffe.dockerfile index 66b784eb8e0..b63044e65c2 100644 --- a/frameworks/FSharp/giraffe/giraffe.dockerfile +++ b/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 diff --git a/frameworks/FSharp/giraffe/src/App/App.fsproj b/frameworks/FSharp/giraffe/src/App/App.fsproj index db327a4549e..bbdd52ee3af 100644 --- a/frameworks/FSharp/giraffe/src/App/App.fsproj +++ b/frameworks/FSharp/giraffe/src/App/App.fsproj @@ -1,18 +1,15 @@ - net7.0 + net8.0 false - - - true - - - - + + + + diff --git a/frameworks/FSharp/giraffe/src/App/Program.fs b/frameworks/FSharp/giraffe/src/App/Program.fs index 4967b043d06..ce8514699cd 100644 --- a/frameworks/FSharp/giraffe/src/App/Program.fs +++ b/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 - [] + [] 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 \ No newline at end of file diff --git a/frameworks/FSharp/zebra/README.md b/frameworks/FSharp/zebra/README.md index 744b571dba1..0dfe791d8cc 100644 --- a/frameworks/FSharp/zebra/README.md +++ b/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** diff --git a/frameworks/FSharp/zebra/src/App/App.fsproj b/frameworks/FSharp/zebra/src/App/App.fsproj index 0b11a353111..87f9f551340 100644 --- a/frameworks/FSharp/zebra/src/App/App.fsproj +++ b/frameworks/FSharp/zebra/src/App/App.fsproj @@ -1,20 +1,18 @@  - net7.0 + net8.0 portable App Exe false - - true - - + + - + diff --git a/frameworks/FSharp/zebra/zebra-simple.dockerfile b/frameworks/FSharp/zebra/zebra-simple.dockerfile index 840dd1a2fdd..b02a6c8977f 100644 --- a/frameworks/FSharp/zebra/zebra-simple.dockerfile +++ b/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 diff --git a/frameworks/FSharp/zebra/zebra.dockerfile b/frameworks/FSharp/zebra/zebra.dockerfile index b0c2d9ec661..a43c8eb1c5c 100644 --- a/frameworks/FSharp/zebra/zebra.dockerfile +++ b/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 diff --git a/frameworks/JavaScript/nodejs/app.js b/frameworks/JavaScript/nodejs/app.js index 95c97a34291..b118b71bc61 100755 --- a/frameworks/JavaScript/nodejs/app.js +++ b/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); diff --git a/frameworks/JavaScript/nodejs/create-server.js b/frameworks/JavaScript/nodejs/create-server.js index b0e142deb1a..38fdb6c938c 100644 --- a/frameworks/JavaScript/nodejs/create-server.js +++ b/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) diff --git a/frameworks/JavaScript/nodejs/handlers/postgres.js b/frameworks/JavaScript/nodejs/handlers/postgres.js index c7411c64fad..3d6eee29872 100644 --- a/frameworks/JavaScript/nodejs/handlers/postgres.js +++ b/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`; diff --git a/frameworks/Kotlin/http4k/core-pgclient/src/main/kotlin/PostgresDatabase.kt b/frameworks/Kotlin/http4k/core-pgclient/src/main/kotlin/PostgresDatabase.kt index 936dd020a7e..e9b55d4c177 100644 --- a/frameworks/Kotlin/http4k/core-pgclient/src/main/kotlin/PostgresDatabase.kt +++ b/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() - override fun updateWorlds(count: Int) = - Future.all((1..count) - .map { queryPool.findWorld(random.world()) }) - .map>(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() diff --git a/frameworks/Python/aiohttp/requirements.txt b/frameworks/Python/aiohttp/requirements.txt index 91fb238338d..bb7f19ececa 100644 --- a/frameworks/Python/aiohttp/requirements.txt +++ b/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 diff --git a/frameworks/Python/api_hour/requirements.txt b/frameworks/Python/api_hour/requirements.txt index 9d8070bed79..8fb8905ca36 100644 --- a/frameworks/Python/api_hour/requirements.txt +++ b/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 diff --git a/frameworks/Ruby/hanami/config/auto_tune.rb b/frameworks/Ruby/hanami/config/auto_tune.rb index fbb495c6647..476ed1a45bd 100644 --- a/frameworks/Ruby/hanami/config/auto_tune.rb +++ b/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) diff --git a/frameworks/Ruby/rack/config/auto_tune.rb b/frameworks/Ruby/rack/config/auto_tune.rb index fbb495c6647..476ed1a45bd 100755 --- a/frameworks/Ruby/rack/config/auto_tune.rb +++ b/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) diff --git a/frameworks/Ruby/rails/config/database.yml b/frameworks/Ruby/rails/config/database.yml index 8fa7b78a4e1..ae7de0910d7 100644 --- a/frameworks/Ruby/rails/config/database.yml +++ b/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 diff --git a/frameworks/Rust/gotham/gotham.dockerfile b/frameworks/Rust/gotham/gotham.dockerfile index 197ca3dc0a8..aec3a1dc178 100644 --- a/frameworks/Rust/gotham/gotham.dockerfile +++ b/frameworks/Rust/gotham/gotham.dockerfile @@ -1,4 +1,4 @@ -FROM rust:1.60 +FROM rust:1.65 WORKDIR /gotham COPY ./src ./src diff --git a/frameworks/Rust/ntex/src/main.rs b/frameworks/Rust/ntex/src/main.rs index 9fdbdf4c4c0..c9220d83247 100644 --- a/frameworks/Rust/ntex/src/main.rs +++ b/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 } diff --git a/frameworks/Rust/ntex/src/main_db.rs b/frameworks/Rust/ntex/src/main_db.rs index 14c37112faa..8354a41fd21 100644 --- a/frameworks/Rust/ntex/src/main_db.rs +++ b/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 } diff --git a/frameworks/Rust/ntex/src/main_plt.rs b/frameworks/Rust/ntex/src/main_plt.rs index bf61ec71a87..4e9279d4ebf 100644 --- a/frameworks/Rust/ntex/src/main_plt.rs +++ b/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 } diff --git a/frameworks/Rust/xitca-web/Cargo.lock b/frameworks/Rust/xitca-web/Cargo.lock index 9859419378d..6a87ff4b1fb 100644 --- a/frameworks/Rust/xitca-web/Cargo.lock +++ b/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", diff --git a/frameworks/Rust/xitca-web/Cargo.toml b/frameworks/Rust/xitca-web/Cargo.toml index 8c585273bbe..10af08ac491 100644 --- a/frameworks/Rust/xitca-web/Cargo.toml +++ b/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" } diff --git a/frameworks/Rust/xitca-web/benchmark_config.json b/frameworks/Rust/xitca-web/benchmark_config.json index 4c4ab0e4462..060cb47b354 100755 --- a/frameworks/Rust/xitca-web/benchmark_config.json +++ b/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": "" } } ] diff --git a/frameworks/Rust/xitca-web/rust-toolchain.toml b/frameworks/Rust/xitca-web/rust-toolchain.toml index 310b53dbfd1..3191ef83ece 100644 --- a/frameworks/Rust/xitca-web/rust-toolchain.toml +++ b/frameworks/Rust/xitca-web/rust-toolchain.toml @@ -1,2 +1,2 @@ [toolchain] -channel = "nightly-2023-10-19" +channel = "nightly-2023-11-24" diff --git a/frameworks/Rust/xitca-web/src/main.rs b/frameworks/Rust/xitca-web/src/main.rs index 0d4b226943e..2bc0d5fc720 100755 --- a/frameworks/Rust/xitca-web/src/main.rs +++ b/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>; 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, 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 { 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 { 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) } diff --git a/frameworks/Rust/xitca-web/src/main_axum.rs b/frameworks/Rust/xitca-web/src/main_axum.rs new file mode 100644 index 00000000000..1345569126d --- /dev/null +++ b/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 { + service: RefCell, + _p: PhantomData, + } + + impl TowerHttp { + pub fn service( + service: F, + ) -> impl Service< + Response = impl ReadyService + Service<(TcpStream, SocketAddr)>, + Error = impl fmt::Debug, + > + where + F: Fn() -> Fut + Send + Sync + Clone, + Fut: Future, + S: tower::Service, Response = Response>, + S::Error: fmt::Debug, + B: Body + 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 Service>> for TowerHttp + where + S: tower::Service, Response = Response>, + B: Body + Send + 'static, + B::Error: error::Error + Send + Sync, + { + type Response = Response>; + type Error = S::Error; + + async fn call( + &self, + req: Request>, + ) -> Result { + 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, + } + + impl Body for _RequestBody { + type Data = Bytes; + type Error = io::Error; + + fn poll_data( + self: Pin<&mut Self>, + cx: &mut Context<'_>, + ) -> Poll>> { + Pin::new(&mut *self.get_mut().body).poll_next(cx) + } + + fn poll_trailers( + self: Pin<&mut Self>, + _: &mut Context<'_>, + ) -> Poll, Self::Error>> { + Poll::Ready(Ok(None)) + } + } + + pin_project! { + pub struct ResponseBody { + #[pin] + body: B + } + } + + impl Stream for ResponseBody + where + B: Body, + B::Error: error::Error + Send + Sync + 'static, + { + type Item = Result; + + fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + self.project() + .body + .poll_data(cx) + .map_err(|e| BodyError::from(Box::new(e) as Box)) + } + + fn size_hint(&self) -> (usize, Option) { + 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 _)) + } + } +} diff --git a/frameworks/Rust/xitca-web/src/main_iou.rs b/frameworks/Rust/xitca-web/src/main_iou.rs index b119933e819..7aaa784cef1 100644 --- a/frameworks/Rust/xitca-web/src/main_iou.rs +++ b/frameworks/Rust/xitca-web/src/main_iou.rs @@ -38,18 +38,17 @@ type Request = http::Request>; type Response = http::Response>; 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() } diff --git a/frameworks/Rust/xitca-web/src/main_wasm.rs b/frameworks/Rust/xitca-web/src/main_wasm.rs index cbae01e89c9..f9961afb6ce 100644 --- a/frameworks/Rust/xitca-web/src/main_wasm.rs +++ b/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::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(service: &S, ctx: WebRequest<'_>) -> Result diff --git a/frameworks/Rust/xitca-web/src/util.rs b/frameworks/Rust/xitca-web/src/util.rs index 624b5dcfa95..e9bc8695bd0 100755 --- a/frameworks/Rust/xitca-web/src/util.rs +++ b/frameworks/Rust/xitca-web/src/util.rs @@ -30,6 +30,7 @@ pub type Error = Box; pub type HandleResult = Result; #[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::*; diff --git a/frameworks/Rust/xitca-web/xitca-web-axum.dockerfile b/frameworks/Rust/xitca-web/xitca-web-axum.dockerfile new file mode 100644 index 00000000000..7c45bef27fb --- /dev/null +++ b/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 diff --git a/frameworks/Rust/xitca-web/xitca-web-wasm.dockerfile b/frameworks/Rust/xitca-web/xitca-web-wasm.dockerfile index c11863f4443..08b43318c88 100644 --- a/frameworks/Rust/xitca-web/xitca-web-wasm.dockerfile +++ b/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